sidekiq-superworker 0.1.9 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 014ddac6c1e85e35f8250f215693e183698440bf
4
- data.tar.gz: 573940cf6cdc6b055f870124dbb3d4afc9cc3f0b
3
+ metadata.gz: 53beee36ab3ca54954950636adfc11d3e5d6c8e5
4
+ data.tar.gz: 168d1b43b60f7085b1cb5f3185208d88c94effbd
5
5
  SHA512:
6
- metadata.gz: 6b77c4f34765af555b1efb6a6b7d8c089c47a4a27a6642294c9173cd4804a742495199162ce7ca829a595fd9b3e4082496e8235f77e28c5ff1ee8062e76ea2f5
7
- data.tar.gz: 3433ab2858b6cd155beea4ab729fae4870b985563b99b71cbd915a41e4aa504465d39937e1a4c8c0c204bde424c8d63d3fc3fe0ae55d55e247322902209fbd34
6
+ metadata.gz: f9606cbc54a87383c448ab89ba308df8ca4713caa92920a8d9cb4365c7ede28447ba811e5eced133310b8e32b613ff5f3a56afc51e10cc284141ae2f08cdf218
7
+ data.tar.gz: f2b6beafee29aec0ed97ecf22f334697ea7c235d2886cbd3c95f668e2a8e009303b617a204082b64777fd171ee668700ac32b3cb44fc8cc16518d1466c5d6ffb
data/README.md CHANGED
@@ -1,20 +1,20 @@
1
1
  Sidekiq Superworker
2
2
  ===================
3
- Chain together Sidekiq workers in parallel and/or serial configurations
3
+ Define dependency graphs of Sidekiq jobs
4
4
 
5
5
  Overview
6
6
  --------
7
7
 
8
- Sidekiq Superworker lets you create superworkers, which are simple or complex chains of Sidekiq workers.
8
+ Sidekiq Superworker lets you create superworkers, which are simple or complex graphs of Sidekiq workers.
9
9
 
10
- For example, you can define complex chains of workers, and even use parallel blocks:
10
+ For example, you can define complex graphs of workers and use both serial and parallel worker configurations:
11
11
 
12
12
  [![](https://raw.github.com/socialpandas/sidekiq-superworker/master/doc/diagram-complex.png)](https://raw.github.com/socialpandas/sidekiq-superworker/master/doc/diagram-complex.png)
13
13
 
14
14
  *(Worker10 will run after Worker5, Worker7, Worker8, and Worker9 have all completed.)*
15
15
 
16
16
  ```ruby
17
- Superworker.create(:MySuperworker, :user_id, :comment_id) do
17
+ Superworker.define(:MySuperworker, :user_id, :comment_id) do
18
18
  Worker1 :user_id
19
19
  Worker2 :user_id do
20
20
  parallel do
@@ -41,12 +41,12 @@ And you can run it like any other worker:
41
41
  MySuperworker.perform_async(23, 852)
42
42
  ```
43
43
 
44
- You can also define simple serial chains of workers:
44
+ You can also define simple serial sequences of workers:
45
45
 
46
46
  [![](https://raw.github.com/socialpandas/sidekiq-superworker/master/doc/diagram-simple.png)](https://raw.github.com/socialpandas/sidekiq-superworker/master/doc/diagram-simple.png)
47
47
 
48
48
  ```ruby
49
- Superworker.create(:MySuperworker, :user_id, :comment_id) do
49
+ Superworker.define(:MySuperworker, :user_id, :comment_id) do
50
50
  Worker1 :user_id, :comment_id
51
51
  Worker2 :comment_id
52
52
  Worker3 :user_id
@@ -60,11 +60,6 @@ Include it in your Gemfile:
60
60
 
61
61
  gem 'sidekiq-superworker'
62
62
 
63
- Install and run the migration:
64
-
65
- rails g sidekiq:superworker:install
66
- rake db:migrate
67
-
68
63
  Usage
69
64
  -----
70
65
 
@@ -73,12 +68,12 @@ First, define a superworker in a file that's included during the initialization
73
68
  ```ruby
74
69
  # config/initializers/superworkers.rb
75
70
 
76
- Superworker.create(:MySuperworker, :user_id, :comment_id) do
71
+ Superworker.define(:MySuperworker, :user_id, :comment_id) do
77
72
  Worker1 :user_id, :comment_id
78
73
  Worker2 :comment_id
79
74
  end
80
75
 
81
- Superworker.create(:MyOtherSuperworker, :comment_id) do
76
+ Superworker.define(:MyOtherSuperworker, :comment_id) do
82
77
  Worker2 :comment_id
83
78
  Worker3 :comment_id
84
79
  end
@@ -95,7 +90,7 @@ MySuperworker.perform_async(23, 852)
95
90
  You can define any number of arguments for the superworker and pass them to different subworkers as you see fit:
96
91
 
97
92
  ```ruby
98
- Superworker.create(:MySuperworker, :user_id, :comment_id) do
93
+ Superworker.define(:MySuperworker, :user_id, :comment_id) do
99
94
  Worker1 :user_id, :comment_id
100
95
  Worker2 :comment_id
101
96
  Worker3 :user_id
@@ -105,7 +100,7 @@ end
105
100
  If you want to set any static arguments for the subworkers, you can do that by using any values that are not symbols (e.g. strings, integers, etc):
106
101
 
107
102
  ```ruby
108
- Superworker.create(:MySuperworker, :user_id, :comment_id) do
103
+ Superworker.define(:MySuperworker, :user_id, :comment_id) do
109
104
  Worker1 100, :user_id, :comment_id
110
105
  Worker2 'all'
111
106
  end
@@ -114,7 +109,7 @@ end
114
109
  If a subworker doesn't take any arguments, you'll need to include parentheses after it:
115
110
 
116
111
  ```ruby
117
- Superworker.create(:MySuperworker, :user_id, :comment_id) do
112
+ Superworker.define(:MySuperworker, :user_id, :comment_id) do
118
113
  Worker1 :user_id, :comment_id
119
114
  Worker2()
120
115
  end
@@ -125,20 +120,20 @@ end
125
120
  To refer to a namespaced worker (e.g. `MyModule::Worker1`), replace the two colons with two underscores:
126
121
 
127
122
  ```ruby
128
- Superworker.create(:MySuperworker, :user_id, :comment_id) do
123
+ Superworker.define(:MySuperworker, :user_id, :comment_id) do
129
124
  MyModule__Worker1 :user_id, :comment_id
130
125
  end
131
126
  ```
132
127
 
133
128
  ### Options
134
129
 
135
- #### Insert Method
130
+ #### Delete subjobs after their superjob completes
136
131
 
137
- When a superjob is queued, records for all of its subjobs are created. By default, each subjob record will be created using a separate insert query. If you're creating superjobs with large numbers of subjobs and want to improve performance, you can create these records using a multiple insert query instead. To this, set `:insert_method` to `:multiple`:
132
+ When a superjob is queued, records for all of its subjobs are created. By default these records are deleted when the superjob finished. This can be changed by setting the following option to false:
138
133
 
139
134
  ```ruby
140
135
  # config/initializers/superworker.rb
141
- Sidekiq::Superworker.options[:insert_method] = :multiple
136
+ Sidekiq::Superworker.options[:delete_subjobs_after_superjob_completes] = false
142
137
  ```
143
138
 
144
139
  ### Logging
@@ -154,14 +149,14 @@ Sidekiq::Superworker::Logging.logger = logger
154
149
 
155
150
  ### Monitoring
156
151
 
157
- Using [sidekiq_monitor](https://github.com/socialpandas/sidekiq_monitor) with Sidekiq Superworker is strongly encouraged, as it lets you easily monitor when a superjob is running, when it has finished, whether it has encountered errors, and the status of all of its subjobs.
152
+ Using [sidekiq_monitor](https://github.com/socialpandas/sidekiq_monitor) with Sidekiq Superworker is encouraged, as it lets you easily monitor when a superjob is running, when it has finished, whether it has encountered errors, and the status of all of its subjobs.
158
153
 
159
154
  ### Batch Jobs
160
155
 
161
156
  By using a `batch` block, you can create batches of subjobs that are all associated with the superjob. The following will run Worker1 and Worker2 in serial for every user ID in the array passed to perform_async.
162
157
 
163
158
  ```ruby
164
- Superworker.create(:MyBatchSuperworker, :user_ids) do
159
+ Superworker.define(:MyBatchSuperworker, :user_ids) do
165
160
  batch user_ids: :user_id do
166
161
  Worker1 :user_id
167
162
  Worker2 :user_id
@@ -174,7 +169,7 @@ MyBatchSuperworker.perform_async([30, 31, 32, 33, 34, 35])
174
169
  You can also use multiple arguments:
175
170
 
176
171
  ```ruby
177
- Superworker.create(:MyBatchSuperworker, :user_ids, :comment_ids) do
172
+ Superworker.define(:MyBatchSuperworker, :user_ids, :comment_ids) do
178
173
  batch user_ids: :user_id, comment_ids: :comment_id do
179
174
  Worker1 :user_id, :comment_id
180
175
  Worker2 :user_id
@@ -215,6 +210,28 @@ If a subjob encounters an exception, the subjobs that depend on it won't run, bu
215
210
 
216
211
  If sidekiq_monitor is being used, the exception will be bubbled up to the superjob, which lets you easily see when your superjobs have failed.
217
212
 
213
+ Upgrading to 1.x
214
+ ----------------
215
+
216
+ If you were previously using Sidekiq Superworker 0.x and are upgrading to 1.x, there are some changes to be aware of:
217
+
218
+ ### Redis replaced ActiveRecord
219
+
220
+ ActiveRecord was used as the datastore in 0.x due to application-specific requirements, but Redis is a far better choice for many reasons, especially given that Sidekiq uses Redis. When upgrading to 1.x, you'll need to let all of your superjobs complete, then upgrade to 1.x, then resume running superjobs. You can drop the 'sidekiq_superworker_subjobs' table, if you like.
221
+
222
+ ### Superworker.define replaced Superworker.create
223
+
224
+ The name of the `Superworker.create` method caused confusion, as some users would call it multiple times. Since it defines a class, it's been renamed to `Superworker.define`. You'll need to replace it accordingly.
225
+
226
+ Testing
227
+ -------
228
+
229
+ Sidekiq Superworker is tested against multiple sets of gem dependencies (currently: no gems, Rails 3, and Rails 4), so please run the tests with [Appraisal](https://github.com/thoughtbot/appraisal) before submitting a PR. Thanks!
230
+
231
+ ```bash
232
+ appraisal rspec
233
+ ```
234
+
218
235
  License
219
236
  -------
220
237
 
data/Rakefile CHANGED
@@ -2,11 +2,6 @@
2
2
  require "bundler/gem_tasks"
3
3
  require "rake/testtask"
4
4
 
5
- task :default => :test
5
+ require 'rspec/core/rake_task'
6
6
 
7
- Rake::TestTask.new do |t|
8
- t.libs << "lib"
9
- t.libs << "test"
10
- t.test_files = FileList["test/**/*_test.rb"]
11
- t.verbose = true
12
- end
7
+ RSpec::Core::RakeTask.new('spec')
@@ -1 +1,3 @@
1
- require 'sidekiq/superworker'
1
+ require 'active_model'
2
+ require 'active_support/all'
3
+ require 'sidekiq/superworker'
@@ -1,16 +1,15 @@
1
1
  require 'sidekiq'
2
- require 'activerecord-import'
3
2
 
4
3
  directory = File.dirname(File.absolute_path(__FILE__))
5
4
  require "#{directory}/client_ext.rb"
6
- Dir.glob("#{directory}/superworker/**/*.rb") { |file| require file }
7
- Dir.glob("#{directory}/../generators/sidekiq/superworker/**/*.rb") { |file| require file }
8
- Dir.glob("#{directory}/../../app/models/sidekiq/superworker/*.rb") { |file| require file }
5
+ Dir.glob("#{directory}/superworker/*.rb") { |file| require file }
6
+ Dir.glob("#{directory}/superworker/server/*.rb") { |file| require file }
9
7
 
10
8
  module Sidekiq
11
9
  module Superworker
12
10
  DEFAULTS = {
13
- insert_method: :single
11
+ delete_subjobs_after_superjob_completes: true,
12
+ subjob_redis_prefix: 'subjob'
14
13
  }
15
14
 
16
15
  def self.options
@@ -29,9 +28,6 @@ module Sidekiq
29
28
  logger.debug(message)
30
29
  end
31
30
 
32
- def self.table_name_prefix
33
- 'sidekiq_superworker_'
34
- end
35
31
  end
36
32
  end
37
33
 
@@ -44,28 +40,5 @@ end
44
40
  Superworker = Sidekiq::Superworker::Worker unless Object.const_defined?('Superworker')
45
41
 
46
42
  if defined?(Sidekiq::Monitor)
47
-
48
- # Make Cleaner ignore superjobs, as they don't exist in Redis and thus won't be synced with Sidekiq::Monitor::Job
49
- Sidekiq::Monitor::Cleaner.add_ignored_queue(Sidekiq::Superworker::SuperjobProcessor.queue_name) if defined?(Sidekiq::Monitor)
50
-
51
- # Add a custom view that shows the subjobs for a superjob
52
- custom_views_directory = "#{directory}/../../app/views/sidekiq/superworker/subjobs"
53
- Sidekiq::Monitor::CustomViews.add 'Subjobs', custom_views_directory do |job|
54
- job.queue == Sidekiq::Superworker::SuperjobProcessor.queue_name.to_s
55
- end
56
-
57
- # Add a "superjob:{id}" search filter
58
- Sidekiq::Monitor::JobsDatatable.add_search_filter({
59
- pattern: /^superjob:([\d]+)$/,
60
- filter: lambda do |search_term, records|
61
- superjob_id = search_term[/^superjob:([\d]+)$/, 1]
62
- superjob = Sidekiq::Monitor::Job.find_by_id(superjob_id)
63
- # Return empty set
64
- return records.where(id: nil) unless superjob
65
- superjob_jid = superjob.jid
66
- subjob_jids = Sidekiq::Superworker::Subjob.where(superjob_id: superjob_jid).map(&:jid).compact
67
- records.where(jid: subjob_jids + [superjob_jid])
68
- end
69
- })
70
-
43
+ require "#{directory}/superworker/integrations/sidekiq_monitor"
71
44
  end
@@ -91,7 +91,8 @@ module Sidekiq
91
91
  subworker_class: 'batch_child',
92
92
  arg_keys: iteration_keys,
93
93
  arg_values: iteration_args.values,
94
- parent_id: batch_id
94
+ parent_id: batch_id,
95
+ children_ids: []
95
96
  }
96
97
  @records[batch_child_id] = batch_child
97
98
 
@@ -109,6 +110,7 @@ module Sidekiq
109
110
  @records[last_subjob_id][:next_id] = subjob_id if last_subjob_id
110
111
  last_subjob_id = subjob_id
111
112
  nested_hash_to_records(children, parent_id: subjob_id, scoped_args: iteration_args)
113
+ batch_child[:children_ids] << subjob_id
112
114
  end
113
115
 
114
116
  children_ids << batch_child_id
@@ -0,0 +1,27 @@
1
+ directory = File.dirname(File.absolute_path(__FILE__))
2
+
3
+ # Make Cleaner ignore superjobs, as they don't exist in Redis and thus won't be synced with Sidekiq::Monitor::Job
4
+ Sidekiq::Monitor::Cleaner.add_ignored_queue(Sidekiq::Superworker::SuperjobProcessor.queue_name) if defined?(Sidekiq::Monitor)
5
+
6
+ # Add a custom view that shows the subjobs for a superjob
7
+ custom_views_directory = "#{directory}/../../../../app/views/sidekiq/superworker/subjobs"
8
+ Sidekiq::Monitor::CustomViews.add 'Subjobs', custom_views_directory do |job|
9
+ job.queue == Sidekiq::Superworker::SuperjobProcessor.queue_name.to_s
10
+ end
11
+
12
+ # Add a "superjob:{id}" search filter
13
+ Sidekiq::Monitor::JobsDatatable.add_search_filter({
14
+ pattern: /^superjob:([\d]+)$/,
15
+ filter: lambda do |search_term, records|
16
+ superjob_id = search_term[/^superjob:([\d]+)$/, 1]
17
+ superjob = Sidekiq::Monitor::Job.find_by_id(superjob_id)
18
+ # Return empty set
19
+ return records.where(id: nil) unless superjob
20
+ superjob_jid = superjob.jid
21
+ subjob_jids = Sidekiq::Superworker::Subjob.find_by_superjob_jid(superjob_jid).map(&:jid).compact
22
+ records.where(jid: subjob_jids + [superjob_jid])
23
+ end
24
+ })
25
+
26
+ # If jobs are deleted after a completion
27
+ Sidekiq::Superworker.options[:delete_subjobs_after_superjob_completes] = false
@@ -11,7 +11,7 @@ module Sidekiq
11
11
  raise "Job has nil jid: #{item}" if item['jid'].nil?
12
12
 
13
13
  Superworker.debug "JID ##{item['jid']}: Error thrown"
14
- subjob = find_subjob_by_jid(item['jid'])
14
+ subjob = Subjob.find_by_jid(item['jid'])
15
15
  SubjobProcessor.error(subjob, worker, item, exception) if subjob
16
16
  end
17
17
 
@@ -21,16 +21,9 @@ module Sidekiq
21
21
  raise "Job has nil jid: #{item}" if item['jid'].nil?
22
22
 
23
23
  Superworker.debug "JID ##{item['jid']}: Passing job from Sidekiq to Superworker"
24
- subjob = find_subjob_by_jid(item['jid'])
24
+ subjob = Subjob.find_by_jid(item['jid'])
25
25
  SubjobProcessor.complete(subjob) if subjob
26
26
  end
27
-
28
- # Note: The job may've been created outside of sidekiq-superworker, so a nil return value
29
- # for this method isn't necessarily problematic
30
- def find_subjob_by_jid(jid)
31
- Superworker.debug "JID ##{jid}: Finding Subjob"
32
- Subjob.find_by_jid(jid)
33
- end
34
27
  end
35
28
  end
36
29
  end
@@ -7,16 +7,14 @@ module Sidekiq
7
7
  end
8
8
 
9
9
  def call(worker, item, queue)
10
- ActiveRecord::Base.connection_pool.with_connection do
11
- begin
12
- return_value = yield
13
- rescue Exception => exception
14
- @processor.error(worker, item, queue, exception)
15
- raise exception
16
- end
17
- @processor.complete(item)
18
- return_value
10
+ begin
11
+ return_value = yield
12
+ rescue Exception => exception
13
+ @processor.error(worker, item, queue, exception)
14
+ raise exception
19
15
  end
16
+ @processor.complete(item)
17
+ return_value
20
18
  end
21
19
  end
22
20
  end
@@ -0,0 +1,164 @@
1
+ module Sidekiq
2
+ module Superworker
3
+ class Subjob
4
+ include ActiveModel::Validations
5
+ include ActiveModel::Naming
6
+
7
+ ATTRIBUTES = [:subjob_id, :superjob_id, :parent_id, :children_ids, :next_id, :children_ids,
8
+ :subworker_class, :superworker_class, :arg_keys, :arg_values, :status, :descendants_are_complete,
9
+ :meta]
10
+
11
+ attr_accessor *ATTRIBUTES
12
+
13
+ validates_presence_of :subjob_id, :subworker_class, :superworker_class, :status
14
+
15
+ class << self
16
+ def create(attributes={})
17
+ if attributes.is_a?(Array)
18
+ attributes.collect { |attribute| create(attribute) }
19
+ else
20
+ object = new(attributes)
21
+ object.save
22
+ object
23
+ end
24
+ end
25
+
26
+ def find_by_jid(jid)
27
+ hash = Sidekiq.redis do |conn|
28
+ conn.hgetall("#{redis_prefix}:#{jid}")
29
+ end
30
+ return nil if hash.blank?
31
+ hash.collect do |key, value|
32
+ hash[key] = ActiveSupport::JSON.decode(value)
33
+ end
34
+ new(hash)
35
+ end
36
+
37
+ def find_by_key(key)
38
+ return nil if key.blank?
39
+ jid = key.split(':', 2).last
40
+ find_by_jid(jid)
41
+ end
42
+
43
+ def find_by_superjob_jid(jid)
44
+ keys = Sidekiq.redis do |conn|
45
+ conn.keys("#{redis_prefix}:#{jid}:*")
46
+ end
47
+ keys.collect { |key| find_by_key(key) }
48
+ end
49
+
50
+ def all
51
+ keys.collect { |key| find_by_key(key) }
52
+ end
53
+
54
+ def count
55
+ keys.length
56
+ end
57
+
58
+ def keys
59
+ Sidekiq.redis do |conn|
60
+ conn.keys("#{redis_prefix}:*")
61
+ end
62
+ end
63
+
64
+ def delete_subjobs_for(superjob_id)
65
+ Sidekiq.redis do |conn|
66
+ key = self.jid(superjob_id, '*')
67
+ keys = conn.keys("#{redis_prefix}:#{key}")
68
+ conn.del(keys) if keys.any?
69
+ end
70
+ end
71
+
72
+ def transaction(&block)
73
+ result = nil
74
+ Sidekiq.redis do |conn|
75
+ conn.multi do
76
+ result = yield
77
+ end
78
+ end
79
+ result
80
+ end
81
+
82
+ def jid(superjob_id, subjob_id)
83
+ "#{superjob_id}:#{subjob_id}"
84
+ end
85
+
86
+ def redis_prefix
87
+ Superworker.options[:subjob_redis_prefix]
88
+ end
89
+ end
90
+
91
+ def initialize(params={})
92
+ if params.present?
93
+ params.each do |attribute, value|
94
+ self.public_send("#{attribute}=", value)
95
+ end
96
+ end
97
+ end
98
+
99
+ def save
100
+ return false unless self.valid?
101
+ Sidekiq.redis do |conn|
102
+ conn.mapped_hmset(key, to_param)
103
+ end
104
+ true
105
+ end
106
+
107
+ def update_attributes(pairs = {})
108
+ pairs.each_pair { |attribute, value| send("#{attribute}=", value) }
109
+ self.save
110
+ end
111
+
112
+ def update_attribute(attribute, value)
113
+ send("#{attribute.to_s}=", value)
114
+ return false unless self.valid?
115
+ Sidekiq.redis do |conn|
116
+ conn.hset(key, attribute.to_s, value.to_json)
117
+ end
118
+ true
119
+ end
120
+
121
+ def jid
122
+ self.class.jid(superjob_id, subjob_id)
123
+ end
124
+
125
+ def key
126
+ "#{self.class.redis_prefix}:#{jid}"
127
+ end
128
+
129
+ def descendants_are_complete
130
+ @descendants_are_complete || false
131
+ end
132
+
133
+ def parent
134
+ self.class.find_by_jid(self.class.jid(superjob_id, parent_id))
135
+ end
136
+
137
+ def children
138
+ return [] if children_ids.blank?
139
+ children = children_ids.collect { |id| self.class.find_by_jid(self.class.jid(superjob_id,id)) }
140
+ children.reject(&:nil?)
141
+ end
142
+
143
+ def next
144
+ self.class.find_by_jid(self.class.jid(superjob_id,next_id))
145
+ end
146
+
147
+ def ==(other)
148
+ self.jid == other.jid
149
+ end
150
+
151
+ def to_info
152
+ "Subjob ##{jid} (#{superworker_class} > #{subworker_class})"
153
+ end
154
+
155
+ def to_param
156
+ param = {}
157
+ ATTRIBUTES.each do |attribute|
158
+ param["#{attribute.to_s}".to_sym] = send(attribute).to_json
159
+ end
160
+ param
161
+ end
162
+ end
163
+ end
164
+ end
@@ -38,9 +38,8 @@ module Sidekiq
38
38
  # the job fires off. If the job started first, it could finish before the ActiveRecord update
39
39
  # transaction completes, causing a race condition when finding the ActiveRecord record in
40
40
  # Processor#complete.
41
- jid = SecureRandom.hex(12)
41
+ jid = subjob.jid
42
42
  subjob.update_attributes(
43
- jid: jid,
44
43
  status: 'queued'
45
44
  )
46
45
  enqueue_in_sidekiq(subjob, klass, jid)
@@ -26,13 +26,15 @@ module Sidekiq
26
26
  end
27
27
 
28
28
  # Enqueue the first root-level subjob
29
- first_subjob = subjobs.select{ |subjob| subjob.parent_id.nil? }.first
29
+ first_subjob = subjobs.find { |subjob| subjob.parent_id.nil? }
30
30
  SubjobProcessor.enqueue(first_subjob)
31
31
  end
32
32
 
33
33
  def self.complete(superjob_id)
34
34
  Superworker.debug "Superworker ##{superjob_id}: Complete"
35
35
 
36
+ Subjob.delete_subjobs_for(superjob_id) if Superworker.options[:delete_subjobs_after_superjob_completes]
37
+
36
38
  # Set the superjob Sidekiq::Monitor::Job as being complete
37
39
  if defined?(Sidekiq::Monitor)
38
40
  job = Sidekiq::Monitor::Job.where(queue: queue_name, jid: superjob_id).first
@@ -1,5 +1,5 @@
1
1
  module Sidekiq
2
2
  module Superworker
3
- VERSION = '0.1.9'
3
+ VERSION = '1.0.0'
4
4
  end
5
5
  end
@@ -1,15 +1,19 @@
1
1
  module Sidekiq
2
2
  module Superworker
3
3
  class Worker
4
- def self.create(*args, &block)
4
+ def self.define(*args, &block)
5
5
  class_name = args.shift.to_sym
6
6
  nested_hash = DSLParser.new.parse(block)
7
- create_class(class_name, args, nested_hash)
7
+ define_class(class_name, args, nested_hash)
8
+ end
9
+
10
+ def self.create(*args, &block)
11
+ raise NoMethodError.new("Superworker.create has been replaced by Superworker.define.\nPlease see 'Upgrading to 1.x' at https://github.com/socialpandas/sidekiq-superworker.\nSuperworker.create called at #{caller[0]}")
8
12
  end
9
13
 
10
14
  protected
11
15
 
12
- def self.create_class(class_name, arg_keys, nested_hash)
16
+ def self.define_class(class_name, arg_keys, nested_hash)
13
17
  klass = Class.new(Sidekiq::Superworker::WorkerClass) do
14
18
  @class_name = class_name
15
19
  @arg_keys = arg_keys
@@ -12,6 +12,7 @@ module Sidekiq
12
12
  options = initialize_superjob(arg_values)
13
13
  subjobs = create_subjobs(arg_values, options)
14
14
  SuperjobProcessor.create(@superjob_id, @class_name, arg_values, subjobs, options)
15
+ @superjob_id
15
16
  end
16
17
 
17
18
  protected
@@ -48,19 +49,8 @@ module Sidekiq
48
49
  end
49
50
  record
50
51
  end
51
-
52
- insert_subjobs(records)
53
- end
54
-
55
- def insert_subjobs(records)
56
- if Sidekiq::Superworker.options[:insert_method] == :multiple
57
- subjobs = records.collect { |record| Sidekiq::Superworker::Subjob.new(record) }
58
- Sidekiq::Superworker::Subjob.import(subjobs)
59
- Sidekiq::Superworker::Subjob.where(superjob_id: @superjob_id).order(:subjob_id)
60
- else
61
- Sidekiq::Superworker::Subjob.transaction do
62
- Sidekiq::Superworker::Subjob.create(records)
63
- end
52
+ Sidekiq::Superworker::Subjob.transaction do
53
+ Sidekiq::Superworker::Subjob.create(records)
64
54
  end
65
55
  end
66
56
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sidekiq-superworker
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.9
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tom Benner
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-07-03 00:00:00.000000000 Z
11
+ date: 2014-10-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sidekiq
@@ -25,35 +25,35 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: 2.1.0
27
27
  - !ruby/object:Gem::Dependency
28
- name: activerecord-import
28
+ name: activesupport
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - '>='
32
32
  - !ruby/object:Gem::Version
33
- version: '0'
33
+ version: '3.2'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - '>='
39
39
  - !ruby/object:Gem::Version
40
- version: '0'
40
+ version: '3.2'
41
41
  - !ruby/object:Gem::Dependency
42
- name: rails
42
+ name: activemodel
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ~>
45
+ - - '>='
46
46
  - !ruby/object:Gem::Version
47
47
  version: '3.2'
48
- type: :development
48
+ type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ~>
52
+ - - '>='
53
53
  - !ruby/object:Gem::Version
54
54
  version: '3.2'
55
55
  - !ruby/object:Gem::Dependency
56
- name: sqlite3
56
+ name: appraisal
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - '>='
@@ -67,7 +67,7 @@ dependencies:
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
- name: rspec-rails
70
+ name: rspec
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - ~>
@@ -81,7 +81,7 @@ dependencies:
81
81
  - !ruby/object:Gem::Version
82
82
  version: '2.12'
83
83
  - !ruby/object:Gem::Dependency
84
- name: database_cleaner
84
+ name: rake
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - '>='
@@ -94,7 +94,7 @@ dependencies:
94
94
  - - '>='
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0'
97
- description: Chain together Sidekiq workers in parallel and/or serial configurations
97
+ description: Define dependency graphs of Sidekiq jobs
98
98
  email:
99
99
  - tombenner@gmail.com
100
100
  executables: []
@@ -104,19 +104,17 @@ files:
104
104
  - MIT-LICENSE
105
105
  - README.md
106
106
  - Rakefile
107
- - app/models/sidekiq/superworker/subjob.rb
108
- - app/views/sidekiq/superworker/subjobs.slim
109
- - lib/generators/sidekiq/superworker/install/install_generator.rb
110
- - lib/generators/sidekiq/superworker/install/templates/create_sidekiq_superworker_subjobs.rb
111
107
  - lib/sidekiq-superworker.rb
112
108
  - lib/sidekiq/client_ext.rb
113
109
  - lib/sidekiq/superworker.rb
114
110
  - lib/sidekiq/superworker/dsl_evaluator.rb
115
111
  - lib/sidekiq/superworker/dsl_hash.rb
116
112
  - lib/sidekiq/superworker/dsl_parser.rb
113
+ - lib/sidekiq/superworker/integrations/sidekiq_monitor.rb
117
114
  - lib/sidekiq/superworker/logging.rb
118
115
  - lib/sidekiq/superworker/processor.rb
119
116
  - lib/sidekiq/superworker/server/middleware.rb
117
+ - lib/sidekiq/superworker/subjob.rb
120
118
  - lib/sidekiq/superworker/subjob_processor.rb
121
119
  - lib/sidekiq/superworker/superjob_processor.rb
122
120
  - lib/sidekiq/superworker/version.rb
@@ -145,6 +143,6 @@ rubyforge_project:
145
143
  rubygems_version: 2.2.2
146
144
  signing_key:
147
145
  specification_version: 4
148
- summary: Chain together Sidekiq workers in parallel and/or serial configurations
146
+ summary: Define dependency graphs of Sidekiq jobs
149
147
  test_files: []
150
148
  has_rdoc:
@@ -1,37 +0,0 @@
1
- module Sidekiq
2
- module Superworker
3
- class Subjob < ActiveRecord::Base
4
- attr_accessible :jid, :subjob_id, :superjob_id, :parent_id, :children_ids, :next_id,
5
- :subworker_class, :superworker_class, :arg_keys, :arg_values, :status, :descendants_are_complete,
6
- :meta if ActiveRecord::VERSION::MAJOR < 4 || ActiveRecord.constants.include?(:MassAssignmentSecurity)
7
-
8
- serialize :arg_keys
9
- serialize :arg_values
10
- serialize :children_ids
11
- serialize :meta
12
-
13
- validates_presence_of :subjob_id, :subworker_class, :superworker_class, :status
14
-
15
- def relatives
16
- self.class.where(superjob_id: superjob_id)
17
- end
18
-
19
- def parent
20
- return nil if parent_id.nil?
21
- relatives.where(subjob_id: parent_id).first
22
- end
23
-
24
- def children
25
- relatives.where(parent_id: subjob_id).order(:subjob_id)
26
- end
27
-
28
- def next
29
- relatives.where(subjob_id: next_id).first
30
- end
31
-
32
- def to_info
33
- "Subjob ##{id} (#{superworker_class} > #{subworker_class})"
34
- end
35
- end
36
- end
37
- end
@@ -1,16 +0,0 @@
1
- - subjobs = Sidekiq::Superworker::Subjob.where(superjob_id: job.jid).where('subworker_class != ?', 'batch').order('subjob_id')
2
-
3
- table.table.table-condensed.table-striped.table-hover
4
- tr
5
- th ID
6
- th Class
7
- th Args
8
- th Status
9
- th JID
10
- - subjobs.each do |subjob|
11
- tr
12
- td = subjob.id
13
- td = subjob.subworker_class
14
- td = subjob.arg_values
15
- td = subjob.status
16
- td = subjob.jid
@@ -1,27 +0,0 @@
1
- require 'rails/generators'
2
- require 'rails/generators/base'
3
-
4
- module Sidekiq
5
- module Superworker
6
- module Generators
7
- class InstallGenerator < ::Rails::Generators::Base
8
- include ::Rails::Generators::Migration
9
- source_root File.expand_path('../templates', __FILE__)
10
- desc "Install the migrations"
11
-
12
- def self.next_migration_number(path)
13
- unless @prev_migration_nr
14
- @prev_migration_nr = Time.now.utc.strftime("%Y%m%d%H%M%S").to_i
15
- else
16
- @prev_migration_nr += 1
17
- end
18
- @prev_migration_nr.to_s
19
- end
20
-
21
- def install_migrations
22
- migration_template "create_sidekiq_superworker_subjobs.rb", "db/migrate/create_sidekiq_superworker_subjobs.rb"
23
- end
24
- end
25
- end
26
- end
27
- end
@@ -1,26 +0,0 @@
1
- class CreateSidekiqSuperworkerSubjobs < ActiveRecord::Migration
2
- def change
3
- create_table :sidekiq_superworker_subjobs do |t|
4
- t.string :jid
5
- t.string :superjob_id, null: false
6
- t.integer :subjob_id, null: false
7
- t.integer :parent_id
8
- t.text :children_ids
9
- t.integer :next_id
10
- t.string :superworker_class, null: false
11
- t.string :subworker_class, null: false
12
- t.text :arg_keys
13
- t.text :arg_values
14
- t.string :status, null: false
15
- t.boolean :descendants_are_complete, default: false
16
- t.text :meta
17
-
18
- t.timestamps
19
- end
20
-
21
- add_index :sidekiq_superworker_subjobs, :jid
22
- add_index :sidekiq_superworker_subjobs, :subjob_id
23
- add_index :sidekiq_superworker_subjobs, [:superjob_id, :subjob_id]
24
- add_index :sidekiq_superworker_subjobs, [:superjob_id, :parent_id]
25
- end
26
- end