postqueue 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 922c5d4f8d07a93c7e889709d136de7159014599
4
+ data.tar.gz: fb6d7ac28ed62728a688a4e1cf8f7b6120626b55
5
+ SHA512:
6
+ metadata.gz: d9371b02973a1ff7776daa9f0f2dac442723acc42d52c4745497438d261fbdd5956178af4d56aea962d9cd5f040a112f9be834c25d7602b4c01b913bf417b3d8
7
+ data.tar.gz: 0172ea33447642ca43b836b662a52401bae80810940dfd54e24d423600b7462d5b2a9f9376ce35e0b6a46598cd438de3989f4b6d6ea228c7c494aa8f651c5ae7
data/README.md ADDED
@@ -0,0 +1,41 @@
1
+ # Postqueue
2
+
3
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/postqueue`. To experiment with that code, run `bin/console` for an interactive prompt.
4
+
5
+ TODO: Delete this and the text above, and describe your gem
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'postqueue'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install postqueue
22
+
23
+ ## Usage
24
+
25
+ TODO: Write usage instructions here
26
+
27
+ ## Development
28
+
29
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
30
+
31
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
32
+
33
+ ## Contributing
34
+
35
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/postqueue.
36
+
37
+
38
+ ## License
39
+
40
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
41
+
@@ -0,0 +1,23 @@
1
+ module Postqueue
2
+ module Enqueue
3
+ Item = ::Postqueue::Item
4
+
5
+ def enqueue(op:, entity_type:, entity_id:)
6
+ # An optimized code path, as laid out below, is 4 times as fast.
7
+ # However, exec_query changed from Rails 4 to Rails 5.
8
+
9
+ # sql = "INSERT INTO postqueue (op, entity_type, entity_id) VALUES($1, $2, $3)"
10
+ # binds = [ ]
11
+ #
12
+ # binds << ActiveRecord::Attribute.from_user("name", op, ::ActiveRecord::Type::String.new)
13
+ # binds << ActiveRecord::Attribute.from_user("entity_type", entity_type, ::ActiveRecord::Type::String.new)
14
+ # binds << ActiveRecord::Attribute.from_user("entity_id", entity_id, ::ActiveRecord::Type::Integer.new)
15
+ # # Note: Rails 4 does not understand prepare: true
16
+ # db.exec_query(sql, 'SQL', binds, prepare: true)
17
+
18
+ Item.create!(op: op, entity_type: entity_type, entity_id: entity_id)
19
+ end
20
+ end
21
+
22
+ extend Enqueue
23
+ end
@@ -0,0 +1,30 @@
1
+ require "active_record"
2
+
3
+ module Postqueue
4
+ class Item < ActiveRecord::Base
5
+ self.table_name = :postqueue
6
+ end
7
+
8
+ def self.unmigrate!
9
+ Item.connection.execute <<-SQL
10
+ DROP TABLE IF EXISTS postqueue;
11
+ SQL
12
+ end
13
+
14
+ def self.migrate!
15
+ Item.connection.execute <<-SQL
16
+ CREATE TABLE postqueue (
17
+ id SERIAL PRIMARY KEY,
18
+ op VARCHAR,
19
+ entity_type VARCHAR,
20
+ entity_id INTEGER NOT NULL DEFAULT 0,
21
+ created_at timestamp without time zone NOT NULL DEFAULT (now() at time zone 'utc'),
22
+ next_run_at timestamp without time zone NOT NULL DEFAULT (now() at time zone 'utc'),
23
+ failed_attempts INTEGER NOT NULL DEFAULT 0
24
+ );
25
+
26
+ CREATE INDEX postqueue_idx1 ON postqueue(entity_id);
27
+ CREATE INDEX postqueue_idx2 ON postqueue(next_run_at);
28
+ SQL
29
+ end
30
+ end
@@ -0,0 +1,97 @@
1
+ module Postqueue
2
+ MAX_ATTEMPTS = 3
3
+
4
+ module Processing
5
+ # Processes many entries
6
+ #
7
+ # process limit: 100, skip_duplicates: true
8
+ def process(options = {}, &block)
9
+ limit = options.fetch(:limit, 100)
10
+ skip_duplicates = options.fetch(:skip_duplicates, true)
11
+ options.delete :limit
12
+ options.delete :skip_duplicates
13
+
14
+ status, result = Item.transaction do
15
+ process_inside_transaction options, limit: limit, skip_duplicates: skip_duplicates, &block
16
+ end
17
+
18
+ raise result if status == :err
19
+ result
20
+ end
21
+
22
+ # Process a single entry from the queue
23
+ #
24
+ # Example:
25
+ #
26
+ # process_one do |op, entity_type
27
+ # end
28
+ def process_one(options = {}, &block)
29
+ options = options.merge(limit: 1, skip_duplicates: false)
30
+ process options, &block
31
+ end
32
+
33
+ private
34
+
35
+ def select_and_lock(relation, limit:)
36
+ relation = relation.where("failed_attempts < ? AND next_run_at < ?", MAX_ATTEMPTS, Time.now).order(:next_run_at, :id)
37
+
38
+ sql = relation.to_sql + " FOR UPDATE SKIP LOCKED"
39
+ sql += " LIMIT #{limit}" if limit
40
+ items = Item.find_by_sql(sql)
41
+
42
+ items
43
+ end
44
+
45
+ # The actual processing. Returns [ :ok, number-of-items ] or [ :err, exception ]
46
+ def process_inside_transaction(options, limit:, skip_duplicates:, &block)
47
+ relation = Item.all
48
+ relation = relation.where(options[:where]) if options[:where]
49
+
50
+ first_match = select_and_lock(relation, limit: 1).first
51
+ return [ :ok, nil ] unless first_match
52
+
53
+ # find all matching entries with the same entity_type/op value
54
+ if limit > 1
55
+ batch_relation = relation.where(entity_type: first_match.entity_type, op: first_match.op)
56
+ matches = select_and_lock(batch_relation, limit: limit)
57
+ else
58
+ matches = [ first_match ]
59
+ end
60
+
61
+ entity_ids = matches.map(&:entity_id)
62
+
63
+ # When skipping dupes we'll find and lock all entries that match entity_type,
64
+ # op, and one of the entity_ids in the first batch of matches
65
+ if skip_duplicates
66
+ entity_ids.uniq!
67
+ process_relations = relation.where(entity_type: first_match.entity_type, op: first_match.op, entity_id: entity_ids)
68
+ process_items = select_and_lock process_relations, limit: nil
69
+ else
70
+ process_items = matches
71
+ end
72
+
73
+ # Actually process the queue items
74
+ result = [ first_match.op, first_match.entity_type, entity_ids ]
75
+ result = yield *result if block_given?
76
+
77
+ if result == false
78
+ postpone process_items
79
+ else
80
+ Item.where(id: process_items.map(&:id)).delete_all
81
+ end
82
+
83
+ [ :ok, result ]
84
+ rescue => e
85
+ postpone process_items
86
+ [ :err, e ]
87
+ end
88
+
89
+ def postpone(items)
90
+ ids = items.map(&:id)
91
+ sql = "UPDATE postqueue SET failed_attempts = failed_attempts+1, next_run_at = next_run_at + interval '10 second' WHERE id IN (#{ids.join(",")})"
92
+ Item.connection.exec_query(sql)
93
+ end
94
+ end
95
+
96
+ extend Processing
97
+ end
@@ -0,0 +1,3 @@
1
+ module Postqueue
2
+ VERSION = '0.0.1'
3
+ end
data/lib/postqueue.rb ADDED
@@ -0,0 +1,9 @@
1
+ require 'postqueue/item'
2
+ require 'postqueue/enqueue'
3
+ require 'postqueue/processing'
4
+ require 'postqueue/version'
5
+
6
+ module Postqueue
7
+ end
8
+
9
+ # require 'postqueue/railtie' if defined?(Rails)
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+
3
+ describe ::Postqueue::Enqueue do
4
+ before do
5
+ Postqueue.enqueue op: "myop", entity_type: "mytype", entity_id: 12
6
+ end
7
+
8
+ let(:item) { Postqueue::Item.first }
9
+
10
+ it 'enqueues items' do
11
+ expect(item.op).to eq("myop")
12
+ expect(item.entity_type).to eq("mytype")
13
+ expect(item.entity_id).to eq(12)
14
+ end
15
+
16
+ it 'sets defaults' do
17
+ expect(item.created_at).to be > (Time.now - 1.second)
18
+ expect(item.next_run_at).to be > (Time.now - 1.second)
19
+ expect(item.failed_attempts).to eq(0)
20
+ end
21
+ end
@@ -0,0 +1,7 @@
1
+ require 'spec_helper'
2
+
3
+ describe "::Postqueue" do
4
+ it "reports a version" do
5
+ expect(Postqueue::VERSION).to satisfy { |s| s =~ /\d\.\d+\.\d+/ }
6
+ end
7
+ end
@@ -0,0 +1,41 @@
1
+ require 'spec_helper'
2
+
3
+ describe "::Postqueue.process_one" do
4
+ class E < RuntimeError; end
5
+
6
+ before do
7
+ Postqueue.enqueue op: "myop", entity_type: "mytype", entity_id: 12
8
+ end
9
+
10
+ it "fails when block raises an exception and reraises the exception" do
11
+ expect { Postqueue.process_one do |op, type, ids| raise E end }.to raise_error(E)
12
+ expect(items.map(&:entity_id)).to contain_exactly(12)
13
+ end
14
+
15
+ it "fails when block returns false" do
16
+ Postqueue.process_one do |op, type, ids| false end
17
+ expect(items.map(&:entity_id)).to contain_exactly(12)
18
+ end
19
+
20
+ it "keeps item in the queue after failure, with an increased failed_attempt count" do
21
+ called_block = 0
22
+ Postqueue.process_one do called_block += 1; false end
23
+ expect(called_block).to eq(1)
24
+
25
+ expect(items.map(&:entity_id)).to contain_exactly(12)
26
+ expect(items.first.failed_attempts).to eq(1)
27
+ end
28
+
29
+ it "ignores items with a failed_attempt count > MAX_ATTEMPTS" do
30
+ expect(Postqueue::MAX_ATTEMPTS).to be >= 3
31
+ items.update_all(failed_attempts: 3)
32
+
33
+ called_block = 0
34
+ r = Postqueue.process_one do called_block += 1; false end
35
+ expect(r).to eq(nil)
36
+ expect(called_block).to eq(0)
37
+
38
+ expect(items.map(&:entity_id)).to contain_exactly(12)
39
+ expect(items.first.failed_attempts).to eq(3)
40
+ end
41
+ end
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+
3
+ describe "::Postqueue.process_one" do
4
+ before do
5
+ Postqueue.enqueue op: "myop", entity_type: "mytype", entity_id: 12
6
+ Postqueue.enqueue op: "myop", entity_type: "mytype", entity_id: 13
7
+ Postqueue.enqueue op: "myop", entity_type: "mytype", entity_id: 14
8
+ end
9
+
10
+ it "processes one entry" do
11
+ r = Postqueue.process_one
12
+ expect(r).to eq(["myop", "mytype", [12]])
13
+ expect(items.map(&:entity_id)).to contain_exactly(13, 14)
14
+ end
15
+
16
+ it "honors search conditions" do
17
+ Postqueue.enqueue op: "otherop", entity_type: "mytype", entity_id: 112
18
+
19
+ r = Postqueue.process_one(where: { op: "otherop" })
20
+ expect(r).to eq(["otherop", "mytype", [112]])
21
+ expect(items.map(&:entity_id)).to contain_exactly(12, 13, 14)
22
+ end
23
+
24
+ it "yields a block and returns it" do
25
+ Postqueue.enqueue op: "otherop", entity_type: "mytype", entity_id: 112
26
+ r = Postqueue.process_one(where: { op: "otherop" }) do |op, type, ids|
27
+ expect(op).to eq("otherop")
28
+ expect(type).to eq("mytype")
29
+ expect(ids).to eq([112])
30
+ "yihaa"
31
+ end
32
+
33
+ expect(r).to eq("yihaa")
34
+ expect(items.map(&:entity_id)).to contain_exactly(12, 13, 14)
35
+ end
36
+ end
@@ -0,0 +1,83 @@
1
+ require 'spec_helper'
2
+
3
+ describe "::Postqueue.process" do
4
+ context 'when having entries with the same entity_type and op' do
5
+ before do
6
+ Postqueue.enqueue op: "myop", entity_type: "mytype", entity_id: 12
7
+ Postqueue.enqueue op: "myop", entity_type: "mytype", entity_id: 13
8
+ Postqueue.enqueue op: "myop", entity_type: "mytype", entity_id: 14
9
+ end
10
+
11
+ it "processes one entries" do
12
+ r = Postqueue.process limit: 1
13
+ expect(r).to eq(["myop", "mytype", [12]])
14
+ expect(items.map(&:entity_id)).to contain_exactly(13, 14)
15
+ end
16
+
17
+ it "processes two entries" do
18
+ r = Postqueue.process limit: 2
19
+ expect(r).to eq(["myop", "mytype", [12, 13]])
20
+ expect(items.map(&:entity_id)).to contain_exactly(14)
21
+ end
22
+
23
+ it "processes many entries" do
24
+ r = Postqueue.process
25
+ expect(r).to eq(["myop", "mytype", [12, 13, 14]])
26
+ expect(items.map(&:entity_id)).to contain_exactly()
27
+ end
28
+ end
29
+
30
+ context 'when having entries with different entity_type and op' do
31
+ before do
32
+ Postqueue.enqueue op: "myop", entity_type: "mytype", entity_id: 12
33
+ Postqueue.enqueue op: "myop", entity_type: "mytype", entity_id: 13
34
+ Postqueue.enqueue op: "otherop", entity_type: "mytype", entity_id: 14
35
+ Postqueue.enqueue op: "myop", entity_type: "othertype", entity_id: 15
36
+ Postqueue.enqueue op: "otherop", entity_type: "othertype", entity_id: 16
37
+ end
38
+
39
+ it "processes one entries" do
40
+ r = Postqueue.process limit: 1
41
+ expect(r).to eq(["myop", "mytype", [12]])
42
+ expect(items.map(&:entity_id)).to contain_exactly(13, 14, 15, 16)
43
+ end
44
+
45
+ it "processes two entries" do
46
+ r = Postqueue.process limit: 2
47
+ expect(r).to eq(["myop", "mytype", [12, 13]])
48
+ expect(items.map(&:entity_id)).to contain_exactly(14, 15, 16)
49
+ end
50
+
51
+ it "processes only matching entries when asked for more" do
52
+ r = Postqueue.process
53
+ expect(r).to eq(["myop", "mytype", [12, 13]])
54
+ expect(items.map(&:entity_id)).to contain_exactly(14, 15, 16)
55
+ end
56
+
57
+ it "honors search conditions" do
58
+ r = Postqueue.process(where: { op: "otherop" })
59
+ expect(r).to eq(["otherop", "mytype", [14]])
60
+ expect(items.map(&:entity_id)).to contain_exactly(12, 13, 15, 16)
61
+ end
62
+ end
63
+
64
+ context 'when having duplicate entries' do
65
+ before do
66
+ Postqueue.enqueue op: "myop", entity_type: "mytype", entity_id: 12
67
+ Postqueue.enqueue op: "myop", entity_type: "mytype", entity_id: 13
68
+ Postqueue.enqueue op: "myop", entity_type: "mytype", entity_id: 12
69
+ end
70
+
71
+ it "removes duplicates from the queue" do
72
+ r = Postqueue.process limit: 1
73
+ expect(r).to eq(["myop", "mytype", [12]])
74
+ expect(items.map(&:entity_id)).to contain_exactly(13)
75
+ end
76
+
77
+ it "does not remove duplicates when skip_duplicates is set to false" do
78
+ r = Postqueue.process limit: 1, skip_duplicates: false
79
+ expect(r).to eq(["myop", "mytype", [12]])
80
+ expect(items.map(&:entity_id)).to contain_exactly(13, 12)
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,29 @@
1
+ path = File.expand_path('../../mpx/lib', __FILE__)
2
+ $LOAD_PATH.unshift(path) unless $LOAD_PATH.include?(path)
3
+
4
+ ENV['RACK_ENV'] = 'test'
5
+
6
+ require 'rspec'
7
+ require 'pry'
8
+ require 'simplecov'
9
+
10
+ SimpleCov.start do
11
+ minimum_coverage 94
12
+ end
13
+
14
+ require 'postqueue'
15
+ require './spec/support/configure_active_record'
16
+
17
+ def items
18
+ Postqueue::Item.all
19
+ end
20
+
21
+ RSpec.configure do |config|
22
+ config.run_all_when_everything_filtered = true
23
+ config.filter_run focus: (ENV['CI'] != 'true')
24
+ config.expect_with(:rspec) { |c| c.syntax = :expect }
25
+ config.order = 'random'
26
+
27
+ config.before(:all) { }
28
+ config.after { }
29
+ end
@@ -0,0 +1,24 @@
1
+ require 'active_record'
2
+ require_relative './models'
3
+
4
+ $LOAD_PATH << File.dirname(__FILE__)
5
+
6
+ ActiveRecord::Base.establish_connection(adapter: 'postgresql',
7
+ database: 'postqueue_test',
8
+ username: 'postqueue',
9
+ password: 'postqueue')
10
+
11
+ require_relative 'schema.rb'
12
+ require_relative 'models.rb'
13
+
14
+ Postqueue.unmigrate!
15
+ Postqueue.migrate!
16
+
17
+ RSpec.configure do |config|
18
+ config.around(:each) do |example|
19
+ ActiveRecord::Base.connection.transaction do
20
+ example.run
21
+ raise ActiveRecord::Rollback, 'Clean up'
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,123 @@
1
+ __END__
2
+
3
+ require 'ostruct'
4
+
5
+ class MockAssocationInfo < OpenStruct
6
+ def virtual?; mode == :virtual; end
7
+ def belongs_to?; mode == :belongs_to; end
8
+ def habtm?; mode == :has_and_belongs_to_many; end
9
+ end
10
+
11
+ module AnalyticsReflectionStub
12
+ attr :analytics_reflection
13
+ def set_analytics_reflection(hsh)
14
+ @analytics_reflection = OpenStruct.new(hsh)
15
+ end
16
+
17
+ attr :analytics_parent
18
+ def set_analytics_parent(analytics_parent)
19
+ @analytics_parent = analytics_parent
20
+ end
21
+ end
22
+
23
+ class Unicorn < ActiveRecord::Base
24
+ extend AnalyticsReflectionStub
25
+
26
+ def self.name_without_prefix
27
+ 'UnicornWithoutPrefix'
28
+ end
29
+
30
+ validates_presence_of :name
31
+
32
+ set_analytics_reflection associations_by_foreign_keys: {}, analytics_keys: [:name]
33
+ end
34
+
35
+ class Manticore < ActiveRecord::Base
36
+ def self.name_without_prefix
37
+ 'ManticoreWithoutPrefix'
38
+ end
39
+ end
40
+
41
+ class Rider < ActiveRecord::Base
42
+ end
43
+
44
+ class Foal < ActiveRecord::Base
45
+ extend AnalyticsReflectionStub
46
+
47
+ belongs_to :parent, class_name: 'Unicorn'
48
+ has_and_belongs_to_many :riders, class_name: 'Rider'
49
+
50
+ set_analytics_reflection associations_by_foreign_keys:
51
+ {
52
+ parent_id: MockAssocationInfo.new(mode: :belongs_to, klass: Unicorn, name: :parent),
53
+ rider_ids: MockAssocationInfo.new(mode: :has_and_belongs_to_many, klass: Rider, name: :riders),
54
+ stable_ids: MockAssocationInfo.new(mode: :virtual, name: :stables)
55
+ },
56
+ analytics_keys: [:nick_name, :age, :parent]
57
+ set_analytics_parent :parent
58
+ end
59
+
60
+ class Pegasus < ActiveRecord::Base
61
+ extend AnalyticsReflectionStub
62
+
63
+ belongs_to :parent, class_name: 'Foal'
64
+
65
+ set_analytics_reflection associations_by_foreign_keys: { :parent_id => OpenStruct.new(klass: Foal, name: :parent) },
66
+ analytics_keys: [:nick_name, :age, :parent]
67
+ set_analytics_parent :parent
68
+
69
+ attr_reader :affiliation_id
70
+ end
71
+
72
+ class Dragon < ActiveRecord::Base
73
+ def self.name_without_prefix
74
+ 'DragonWithoutPrefix'
75
+ end
76
+
77
+ def describe
78
+ 'yihaa'
79
+ end
80
+
81
+ extend AnalyticsReflectionStub
82
+ end
83
+
84
+ class Asset < ActiveRecord::Base
85
+ extend AnalyticsReflectionStub
86
+ attr_reader :affiliation_id
87
+ end
88
+
89
+ class Product < ActiveRecord::Base
90
+ extend AnalyticsReflectionStub
91
+ attr_reader :affiliation_id
92
+ end
93
+
94
+ class User < ActiveRecord::Base
95
+ extend AnalyticsReflectionStub
96
+ attr_reader :affiliation_id
97
+
98
+ def analytics_title
99
+ "my analytics_title"
100
+ end
101
+ end
102
+
103
+ class Grouping < ActiveRecord::Base
104
+ extend AnalyticsReflectionStub
105
+ attr_reader :affiliation_id
106
+ end
107
+
108
+ class Group < Grouping
109
+ end
110
+
111
+ class MockProductAsset < ActiveRecord::Base
112
+ has_one :asset
113
+ has_one :product
114
+
115
+ attr_accessor :asset, :product
116
+ end
117
+
118
+ class MockGroupUser < ActiveRecord::Base
119
+ has_one :group
120
+ has_one :user
121
+
122
+ attr_accessor :group, :user
123
+ end
@@ -0,0 +1,88 @@
1
+ __END__
2
+
3
+ ActiveRecord::Schema.define do
4
+ self.verbose = false
5
+
6
+ create_table :unicorns, force: true do |t|
7
+ t.string :name, null: false
8
+ t.string :affiliation_id
9
+ end
10
+
11
+ create_table :foals, force: true do |t|
12
+ t.integer :parent_id, null: false
13
+ t.string :nick_name
14
+ t.integer :age
15
+ t.datetime :created_at
16
+ end
17
+
18
+ create_table :riders, force: true do |t|
19
+ t.string :nick_name
20
+ end
21
+
22
+ create_table :foal_riders, force: true do |t|
23
+ t.integer :rider_id
24
+ t.integer :foal_id
25
+ end
26
+
27
+ create_table :pegasus, force: true do |t|
28
+ t.integer :parent_id, null: false
29
+ t.string :nick_name
30
+ t.integer :age
31
+ t.datetime :created_at
32
+ end
33
+
34
+ create_table :mock_product_assets, force: true do |t|
35
+ t.integer :asset_id
36
+ t.string :access_level
37
+ t.integer :product_id
38
+ end
39
+
40
+ create_table :mock_group_users, force: true do |t|
41
+ t.integer :user_id
42
+ t.string :access_level
43
+ t.integer :group_id
44
+ end
45
+
46
+ create_table :assets, force: true
47
+
48
+ create_table :products, force: true
49
+
50
+ create_table :users, force: true do |t|
51
+ t.string :title
52
+ end
53
+
54
+ create_table :groupings, force: true
55
+
56
+ create_table :manticores, force: true do |t|
57
+ t.string :dummy_field
58
+ end
59
+
60
+ create_table :dragons, force: true do |t|
61
+ t.string :full_name
62
+ end
63
+
64
+ execute "INSERT INTO unicorns(affiliation_id, id, name) VALUES('mpx', 1, 'Faith')"
65
+ execute "INSERT INTO unicorns(affiliation_id, id, name) VALUES('mpx', 2, 'Faery')"
66
+ execute "INSERT INTO unicorns(affiliation_id, id, name) VALUES('mpx', 3, 'Yaser')"
67
+
68
+ execute "INSERT INTO foals(id, parent_id, nick_name, age, created_at) VALUES(1, 1, 'Little Faith', 12, 0)"
69
+ execute "INSERT INTO foals(id, parent_id, nick_name, age, created_at) VALUES(2, 1, 'Faith Nick', 9, 0)"
70
+
71
+ execute "INSERT INTO riders(id, nick_name) VALUES(1, 'Storm Rider')"
72
+ execute "INSERT INTO riders(id, nick_name) VALUES(2, 'Desert Rider')"
73
+
74
+ execute "INSERT INTO foal_riders(rider_id, foal_id) VALUES(1, 1)"
75
+ execute "INSERT INTO foal_riders(rider_id, foal_id) VALUES(2, 1)"
76
+
77
+ execute "INSERT INTO pegasus(parent_id, nick_name, age, created_at) VALUES(1, 'Derpy', 12, 0)"
78
+
79
+ execute "INSERT INTO dragons(full_name) VALUES('Chrysophylax Dives')"
80
+ execute "INSERT INTO dragons(full_name) VALUES('Nepomuk')"
81
+ execute "INSERT INTO dragons(full_name) VALUES('Smaug')"
82
+
83
+ execute "INSERT INTO manticores(dummy_field) VALUES('Dumb Manticore')"
84
+
85
+ execute "INSERT INTO users(id, title) VALUES(67, 'sixtyseven')"
86
+
87
+ execute "INSERT INTO groupings(id) VALUES(42)"
88
+ end
metadata ADDED
@@ -0,0 +1,171 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: postqueue
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - radiospiel
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-12-10 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 3.4.0
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 3.4.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: pry
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.10'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.10'
41
+ - !ruby/object:Gem::Dependency
42
+ name: pry-byebug
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 10.5.0
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 10.5.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: simplecov
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 0.7.1
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 0.7.1
83
+ - !ruby/object:Gem::Dependency
84
+ name: activerecord
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '4'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '4'
97
+ - !ruby/object:Gem::Dependency
98
+ name: timecop
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: pg
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ description: a postgres based queue implementation
126
+ email:
127
+ - radiospiel@open-lab.org
128
+ executables: []
129
+ extensions: []
130
+ extra_rdoc_files: []
131
+ files:
132
+ - README.md
133
+ - lib/postqueue.rb
134
+ - lib/postqueue/enqueue.rb
135
+ - lib/postqueue/item.rb
136
+ - lib/postqueue/processing.rb
137
+ - lib/postqueue/version.rb
138
+ - spec/postqueue/enqueue_spec.rb
139
+ - spec/postqueue/postqueue_spec.rb
140
+ - spec/postqueue/process_errors_spec.rb
141
+ - spec/postqueue/process_one_spec.rb
142
+ - spec/postqueue/process_spec.rb
143
+ - spec/spec_helper.rb
144
+ - spec/support/configure_active_record.rb
145
+ - spec/support/models.rb
146
+ - spec/support/schema.rb
147
+ homepage: https://github.com/radiospiel/postqueue
148
+ licenses:
149
+ - MIT
150
+ metadata: {}
151
+ post_install_message:
152
+ rdoc_options: []
153
+ require_paths:
154
+ - lib
155
+ required_ruby_version: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ required_rubygems_version: !ruby/object:Gem::Requirement
161
+ requirements:
162
+ - - ">="
163
+ - !ruby/object:Gem::Version
164
+ version: '0'
165
+ requirements: []
166
+ rubyforge_project:
167
+ rubygems_version: 2.5.1
168
+ signing_key:
169
+ specification_version: 4
170
+ summary: a postgres based queue implementation
171
+ test_files: []