sidekiq-superworker 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/MIT-LICENSE +20 -0
- data/README.md +106 -0
- data/Rakefile +12 -0
- data/app/models/sidekiq/superworker/subjob.rb +31 -0
- data/lib/generators/sidekiq/superworker/install/install_generator.rb +27 -0
- data/lib/generators/sidekiq/superworker/install/templates/create_sidekiq_superworker_subjobs.rb +25 -0
- data/lib/sidekiq/superworker/dsl_evaluator.rb +9 -0
- data/lib/sidekiq/superworker/dsl_parser.rb +78 -0
- data/lib/sidekiq/superworker/processor.rb +31 -0
- data/lib/sidekiq/superworker/server/middleware.rb +16 -0
- data/lib/sidekiq/superworker/subjob_processor.rb +112 -0
- data/lib/sidekiq/superworker/version.rb +5 -0
- data/lib/sidekiq/superworker/worker.rb +72 -0
- data/lib/sidekiq/superworker.rb +22 -0
- data/lib/sidekiq-superworker.rb +1 -0
- metadata +140 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2013 SocialPandas
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
Sidekiq Superworker
|
2
|
+
===================
|
3
|
+
Chain together Sidekiq workers in parallel and/or serial configurations
|
4
|
+
|
5
|
+
Overview
|
6
|
+
--------
|
7
|
+
|
8
|
+
Sidekiq Superworker lets you create superworkers, which are simple or complex chains of Sidekiq workers.
|
9
|
+
|
10
|
+
For example, you can define complex chains of workers, and even use parallel blocks:
|
11
|
+
|
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
|
+
|
14
|
+
*(Worker10 will run after Worker5, Worker7, Worker8, and Worker9 have all completed.)*
|
15
|
+
|
16
|
+
```ruby
|
17
|
+
Superworker.create(:MySuperworker, :user_id, :comment_id) do
|
18
|
+
Worker1 :user_id
|
19
|
+
Worker2 :user_id do
|
20
|
+
parallel do
|
21
|
+
Worker3 :comment_id do
|
22
|
+
Worker4 :comment_id
|
23
|
+
Worker5 :comment_id
|
24
|
+
end
|
25
|
+
Worker6 :user_id do
|
26
|
+
parallel do
|
27
|
+
Worker7 :user_id
|
28
|
+
Worker8 :user_id
|
29
|
+
Worker9 :user_id
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
Worker10 :comment_id
|
34
|
+
end
|
35
|
+
end
|
36
|
+
```
|
37
|
+
|
38
|
+
And you can run it like any other worker:
|
39
|
+
|
40
|
+
```ruby
|
41
|
+
MySuperworker.perform_async(23, 852)
|
42
|
+
```
|
43
|
+
|
44
|
+
You can also define simple serial chains of workers:
|
45
|
+
|
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
|
+
|
48
|
+
```ruby
|
49
|
+
Superworker.create(:MySuperworker, :user_id, :comment_id) do
|
50
|
+
Worker1 :user_id, :comment_id
|
51
|
+
Worker2 :comment_id
|
52
|
+
Worker3 :user_id
|
53
|
+
end
|
54
|
+
```
|
55
|
+
|
56
|
+
If you're also using [sidekiq_monitor](https://github.com/socialpandas/sidekiq_monitor), you can easily monitor when a superworker is running and when it has finished.
|
57
|
+
|
58
|
+
Installation
|
59
|
+
------------
|
60
|
+
|
61
|
+
Include it in your Gemfile:
|
62
|
+
|
63
|
+
gem 'sidekiq-superworker'
|
64
|
+
|
65
|
+
Install and run the migration:
|
66
|
+
|
67
|
+
rails g sidekiq:superworker:install
|
68
|
+
rake db:migrate
|
69
|
+
|
70
|
+
Usage
|
71
|
+
-----
|
72
|
+
|
73
|
+
### Arguments
|
74
|
+
|
75
|
+
You can define any number of arguments for the superworker and pass them to different subworkers as you see fit:
|
76
|
+
|
77
|
+
```ruby
|
78
|
+
Superworker.create(:MySuperworker, :user_id, :comment_id) do
|
79
|
+
Worker1 :user_id, :comment_id
|
80
|
+
Worker2 :comment_id
|
81
|
+
Worker3 :user_id
|
82
|
+
end
|
83
|
+
```
|
84
|
+
|
85
|
+
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):
|
86
|
+
|
87
|
+
```ruby
|
88
|
+
Superworker.create(:MySuperworker, :user_id, :comment_id) do
|
89
|
+
Worker1 100, :user_id, :comment_id
|
90
|
+
Worker2 'all'
|
91
|
+
end
|
92
|
+
```
|
93
|
+
|
94
|
+
If a subworker doesn't take any arguments, you'll need to include parentheses after it:
|
95
|
+
|
96
|
+
```ruby
|
97
|
+
Superworker.create(:MySuperworker, :user_id, :comment_id) do
|
98
|
+
Worker1 :user_id, :comment_id
|
99
|
+
Worker2()
|
100
|
+
end
|
101
|
+
```
|
102
|
+
|
103
|
+
License
|
104
|
+
-------
|
105
|
+
|
106
|
+
Sidekiq Superworker is released under the MIT License. Please see the MIT-LICENSE file for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,31 @@
|
|
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
|
6
|
+
|
7
|
+
serialize :children_ids
|
8
|
+
serialize :arg_keys
|
9
|
+
serialize :arg_values
|
10
|
+
|
11
|
+
validates_presence_of :subjob_id, :subworker_class, :superworker_class, :status
|
12
|
+
|
13
|
+
def relatives
|
14
|
+
self.class.where(superjob_id: superjob_id)
|
15
|
+
end
|
16
|
+
|
17
|
+
def parent
|
18
|
+
return nil if parent_id.nil?
|
19
|
+
relatives.where(subjob_id: parent_id).first
|
20
|
+
end
|
21
|
+
|
22
|
+
def children
|
23
|
+
relatives.where(parent_id: subjob_id).order(:subjob_id)
|
24
|
+
end
|
25
|
+
|
26
|
+
def next
|
27
|
+
relatives.where(subjob_id: next_id).first
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,27 @@
|
|
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
|
data/lib/generators/sidekiq/superworker/install/templates/create_sidekiq_superworker_subjobs.rb
ADDED
@@ -0,0 +1,25 @@
|
|
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
|
+
|
17
|
+
t.timestamps
|
18
|
+
end
|
19
|
+
|
20
|
+
add_index :sidekiq_superworker_subjobs, :jid
|
21
|
+
add_index :sidekiq_superworker_subjobs, :subjob_id
|
22
|
+
add_index :sidekiq_superworker_subjobs, [:superjob_id, :subjob_id]
|
23
|
+
add_index :sidekiq_superworker_subjobs, [:superjob_id, :parent_id]
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
module Sidekiq
|
2
|
+
module Superworker
|
3
|
+
class DSLParser
|
4
|
+
def self.parse(block)
|
5
|
+
@dsl_evaluator = DSLEvaluator.new
|
6
|
+
set_records_from_block(block)
|
7
|
+
{
|
8
|
+
records: @records,
|
9
|
+
nested_records: @nested_records
|
10
|
+
}
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.set_records_from_block(block)
|
14
|
+
@record_id = 0
|
15
|
+
@records = {}
|
16
|
+
@nested_records = block_to_nested_records(block)
|
17
|
+
set_records_from_nested_records(@nested_records)
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.set_records_from_nested_records(nested_records, parent_id=nil)
|
21
|
+
last_id = nil
|
22
|
+
nested_records.each do |id, value|
|
23
|
+
@records[id] = {
|
24
|
+
subjob_id: id,
|
25
|
+
subworker_class: value[:subworker_class].to_s,
|
26
|
+
arg_keys: value[:arg_keys],
|
27
|
+
parent_id: parent_id,
|
28
|
+
children_ids: value[:children] ? value[:children].keys : nil
|
29
|
+
}
|
30
|
+
@records[last_id][:next_id] = id if @records[last_id]
|
31
|
+
last_id = id
|
32
|
+
set_records_from_nested_records(value[:children], id) if value[:children]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.block_to_nested_records(block)
|
37
|
+
fiber = Fiber.new do
|
38
|
+
@dsl_evaluator.instance_eval(&block)
|
39
|
+
end
|
40
|
+
|
41
|
+
nested_records = {}
|
42
|
+
while (method_result = fiber.resume)
|
43
|
+
method, arg_keys, block = method_result
|
44
|
+
@record_id += 1
|
45
|
+
if block
|
46
|
+
nested_records[@record_id] = { subworker_class: method, arg_keys: arg_keys, children: block_to_nested_records(block) }
|
47
|
+
else
|
48
|
+
nested_records[@record_id] = { subworker_class: method, arg_keys: arg_keys }
|
49
|
+
end
|
50
|
+
|
51
|
+
# For superworkers nested within other superworkers, we'll take the subworkers' nested_records,
|
52
|
+
# adjust their ids to fit in with our current @record_id value, and add them into the tree.
|
53
|
+
if method != :parallel
|
54
|
+
subworker_class = method.to_s.constantize
|
55
|
+
if subworker_class.respond_to?(:is_a_superworker?) && subworker_class.is_a_superworker?
|
56
|
+
parent_record_id = @record_id
|
57
|
+
nested_records[parent_record_id][:children] = rewrite_ids_of_subworker_records(subworker_class.nested_records)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
nested_records
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.rewrite_ids_of_subworker_records(nested_records)
|
65
|
+
new_hash = {}
|
66
|
+
nested_records.each do |old_record_id, record|
|
67
|
+
@record_id += 1
|
68
|
+
parent_record_id = @record_id
|
69
|
+
new_hash[parent_record_id] = record
|
70
|
+
if record[:children]
|
71
|
+
new_hash[parent_record_id][:children] = rewrite_ids_of_subworker_records(record[:children])
|
72
|
+
end
|
73
|
+
end
|
74
|
+
new_hash
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Sidekiq
|
2
|
+
module Superworker
|
3
|
+
class Processor
|
4
|
+
def complete(item, new_thread=true)
|
5
|
+
if new_thread
|
6
|
+
# Run this in a new thread so that its execution isn't considered to be part of the
|
7
|
+
# completed job's execution.
|
8
|
+
Thread.new do
|
9
|
+
complete_item(item)
|
10
|
+
end
|
11
|
+
else
|
12
|
+
complete_item(item)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
protected
|
17
|
+
|
18
|
+
def complete_item(item)
|
19
|
+
raise "Job has nil jid: #{item}" if item['jid'].nil?
|
20
|
+
# The job may complete before the Subjob record is created; in case that happens,
|
21
|
+
# we need to sleep briefly and requery.
|
22
|
+
tries = 3
|
23
|
+
while !(subjob = Subjob.find_by_jid(item['jid'])) && tries > 0
|
24
|
+
sleep 1
|
25
|
+
tries -= 1
|
26
|
+
end
|
27
|
+
SubjobProcessor.complete(subjob) if subjob
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Sidekiq
|
2
|
+
module Superworker
|
3
|
+
module Server
|
4
|
+
class Middleware
|
5
|
+
def initialize(options=nil)
|
6
|
+
@processor = Sidekiq::Superworker::Processor.new
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(worker, item, queue)
|
10
|
+
yield
|
11
|
+
@processor.complete(item)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
module Sidekiq
|
2
|
+
module Superworker
|
3
|
+
class SubjobProcessor
|
4
|
+
def self.enqueue(subjob)
|
5
|
+
# Only enqueue subjobs that aren't running, complete, etc
|
6
|
+
return unless subjob.status == 'initialized'
|
7
|
+
|
8
|
+
# If this is a parallel subjob, enqueue all of its children
|
9
|
+
if subjob.subworker_class == 'parallel'
|
10
|
+
subjob.update_attribute(:status, 'running')
|
11
|
+
jids = subjob.children.collect do |child|
|
12
|
+
enqueue(child)
|
13
|
+
end
|
14
|
+
jid = jids.first
|
15
|
+
else
|
16
|
+
klass = "::#{subjob.subworker_class}".constantize
|
17
|
+
|
18
|
+
# If this is a superworker, mark it as complete, which will queue its children or its next subjob
|
19
|
+
if klass.respond_to?(:is_a_superworker?) && klass.is_a_superworker?
|
20
|
+
complete(subjob)
|
21
|
+
# Otherwise, enqueue it in Sidekiq
|
22
|
+
else
|
23
|
+
jid = enqueue_in_sidekiq(subjob, klass)
|
24
|
+
subjob.update_attributes(
|
25
|
+
jid: jid,
|
26
|
+
status: 'queued'
|
27
|
+
)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
jid
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.enqueue_in_sidekiq(subjob, klass)
|
34
|
+
# If sidekiq-unique-jobs is being used for this worker, a number of issues arise if the subjob isn't
|
35
|
+
# queued, so we'll bypass the unique functionality of the worker while running the subjob.
|
36
|
+
is_unique = klass.respond_to?(:sidekiq_options_hash) && !!klass.sidekiq_options_hash['unique']
|
37
|
+
if is_unique
|
38
|
+
unique_value = klass.sidekiq_options_hash.delete('unique')
|
39
|
+
unique_job_expiration_value = klass.sidekiq_options_hash.delete('unique_job_expiration')
|
40
|
+
end
|
41
|
+
|
42
|
+
arg_values = subjob.arg_values
|
43
|
+
jid = klass.perform_async(*arg_values)
|
44
|
+
warn "Nil JID returned by #{subjob.subworker_class}.perform_async with arguments #{arg_values}" if jid.nil?
|
45
|
+
|
46
|
+
if is_unique
|
47
|
+
klass.sidekiq_options_hash['unique'] = unique_value
|
48
|
+
klass.sidekiq_options_hash['unique_job_expiration'] = unique_job_expiration_value
|
49
|
+
end
|
50
|
+
|
51
|
+
jid
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.complete(subjob)
|
55
|
+
subjob.update_attribute(:status, 'complete')
|
56
|
+
|
57
|
+
# If children are present, enqueue the first one
|
58
|
+
children = subjob.children
|
59
|
+
if children.present?
|
60
|
+
enqueue(children.first)
|
61
|
+
return
|
62
|
+
# Otherwise, set this as having its descendants complete
|
63
|
+
else
|
64
|
+
descendants_are_complete(subjob)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.descendants_are_complete(subjob)
|
69
|
+
subjob.update_attribute(:descendants_are_complete, true)
|
70
|
+
|
71
|
+
parent = subjob.parent
|
72
|
+
is_child_of_parallel = parent && parent.subworker_class == 'parallel'
|
73
|
+
|
74
|
+
# If this is a child of a parallel subjob, check to see if the parent's descendants are all complete
|
75
|
+
# and call descendants_are_complete(parent) if so
|
76
|
+
if parent
|
77
|
+
siblings_descendants_are_complete = parent.children.all? { |child| child.descendants_are_complete }
|
78
|
+
if siblings_descendants_are_complete
|
79
|
+
descendants_are_complete(parent)
|
80
|
+
parent.update_attribute(:status, 'complete') if is_child_of_parallel
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
unless is_child_of_parallel
|
85
|
+
# If a next subjob is present, enqueue it
|
86
|
+
next_subjob = subjob.next
|
87
|
+
if next_subjob
|
88
|
+
enqueue(next_subjob)
|
89
|
+
return
|
90
|
+
end
|
91
|
+
|
92
|
+
# Otherwise, if a parent exists, the parent's descendants are complete
|
93
|
+
if parent
|
94
|
+
descendants_are_complete(parent)
|
95
|
+
# Otherwise, this is the final subjob of the superjob
|
96
|
+
else
|
97
|
+
# Set the superjob Sidekiq::Monitor::Job as being complete
|
98
|
+
if defined?(Sidekiq::Monitor)
|
99
|
+
job = Sidekiq::Monitor::Job.where(queue: :superworker, jid: subjob.superjob_id).first
|
100
|
+
if job
|
101
|
+
job.update_attributes(
|
102
|
+
status: 'complete',
|
103
|
+
finished_at: Time.now
|
104
|
+
)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module Sidekiq
|
2
|
+
module Superworker
|
3
|
+
class Worker
|
4
|
+
def self.create(*args, &block)
|
5
|
+
class_name = args.shift.to_sym
|
6
|
+
dsl = DSLParser.parse(block)
|
7
|
+
create_class(class_name, args, dsl)
|
8
|
+
end
|
9
|
+
|
10
|
+
protected
|
11
|
+
|
12
|
+
def self.create_class(class_name, arg_keys, dsl)
|
13
|
+
klass = Class.new do
|
14
|
+
@class_name = class_name
|
15
|
+
@arg_keys = arg_keys
|
16
|
+
@records = dsl[:records]
|
17
|
+
@nested_records = dsl[:nested_records]
|
18
|
+
|
19
|
+
class << self
|
20
|
+
attr_reader :nested_records
|
21
|
+
|
22
|
+
def is_a_superworker?
|
23
|
+
true
|
24
|
+
end
|
25
|
+
|
26
|
+
def perform_async(*arg_values)
|
27
|
+
@args = Hash[@arg_keys.zip(arg_values)]
|
28
|
+
subjobs = create_subjobs
|
29
|
+
|
30
|
+
# Create a Sidekiq::Monitor::Job for the superjob
|
31
|
+
if defined?(Sidekiq::Monitor)
|
32
|
+
now = Time.now
|
33
|
+
Sidekiq::Monitor::Job.create(
|
34
|
+
args: arg_values,
|
35
|
+
class_name: @class_name,
|
36
|
+
enqueued_at: now,
|
37
|
+
jid: @superjob_id,
|
38
|
+
queue: :superworker,
|
39
|
+
started_at: now,
|
40
|
+
status: 'running'
|
41
|
+
)
|
42
|
+
end
|
43
|
+
|
44
|
+
# Enqueue the first root-level subjob
|
45
|
+
first_subjob = subjobs.select{ |subjob| subjob.parent_id.nil? }.first
|
46
|
+
SubjobProcessor.enqueue(first_subjob)
|
47
|
+
end
|
48
|
+
|
49
|
+
protected
|
50
|
+
|
51
|
+
def create_subjobs
|
52
|
+
@superjob_id = SecureRandom.hex(12)
|
53
|
+
@records.collect do |id, record|
|
54
|
+
record[:status] = 'initialized'
|
55
|
+
record[:superjob_id] = @superjob_id
|
56
|
+
record[:superworker_class] = @class_name
|
57
|
+
record[:arg_values] = record[:arg_keys].collect do |arg_key|
|
58
|
+
# Allow for subjob arg_values to be set within the superworker definition; if a symbol is
|
59
|
+
# used in the DSL, use @args[arg_key], and otherwise use arg_key as the value
|
60
|
+
arg_key.is_a?(Symbol) ? @args[arg_key] : arg_key
|
61
|
+
end
|
62
|
+
Sidekiq::Superworker::Subjob.create(record)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
Object.const_set(class_name, klass)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'sidekiq'
|
2
|
+
|
3
|
+
directory = File.dirname(File.absolute_path(__FILE__))
|
4
|
+
Dir.glob("#{directory}/superworker/**/*.rb") { |file| require file }
|
5
|
+
Dir.glob("#{directory}/../generators/sidekiq/superworker/**/*.rb") { |file| require file }
|
6
|
+
Dir.glob("#{directory}/../../app/models/sidekiq/superworker/*.rb") { |file| require file }
|
7
|
+
|
8
|
+
module Sidekiq
|
9
|
+
module Superworker
|
10
|
+
def self.table_name_prefix
|
11
|
+
'sidekiq_superworker_'
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
Sidekiq.configure_server do |config|
|
17
|
+
config.server_middleware do |chain|
|
18
|
+
chain.add Sidekiq::Superworker::Server::Middleware
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
Superworker = Sidekiq::Superworker::Worker unless Object.const_defined?('Superworker')
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'sidekiq/superworker'
|
metadata
ADDED
@@ -0,0 +1,140 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sidekiq-superworker
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Tom Benner
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-06-04 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: sidekiq
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 2.1.0
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 2.1.0
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rails
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: sqlite3
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: rspec-rails
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: database_cleaner
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
description: Chain together Sidekiq workers in parallel and/or serial configurations
|
95
|
+
email:
|
96
|
+
- tombenner@gmail.com
|
97
|
+
executables: []
|
98
|
+
extensions: []
|
99
|
+
extra_rdoc_files: []
|
100
|
+
files:
|
101
|
+
- app/models/sidekiq/superworker/subjob.rb
|
102
|
+
- lib/generators/sidekiq/superworker/install/install_generator.rb
|
103
|
+
- lib/generators/sidekiq/superworker/install/templates/create_sidekiq_superworker_subjobs.rb
|
104
|
+
- lib/sidekiq/superworker/dsl_evaluator.rb
|
105
|
+
- lib/sidekiq/superworker/dsl_parser.rb
|
106
|
+
- lib/sidekiq/superworker/processor.rb
|
107
|
+
- lib/sidekiq/superworker/server/middleware.rb
|
108
|
+
- lib/sidekiq/superworker/subjob_processor.rb
|
109
|
+
- lib/sidekiq/superworker/version.rb
|
110
|
+
- lib/sidekiq/superworker/worker.rb
|
111
|
+
- lib/sidekiq/superworker.rb
|
112
|
+
- lib/sidekiq-superworker.rb
|
113
|
+
- MIT-LICENSE
|
114
|
+
- Rakefile
|
115
|
+
- README.md
|
116
|
+
homepage: https://github.com/socialpandas/sidekiq-superworker
|
117
|
+
licenses: []
|
118
|
+
post_install_message:
|
119
|
+
rdoc_options: []
|
120
|
+
require_paths:
|
121
|
+
- lib
|
122
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
123
|
+
none: false
|
124
|
+
requirements:
|
125
|
+
- - ! '>='
|
126
|
+
- !ruby/object:Gem::Version
|
127
|
+
version: '0'
|
128
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
129
|
+
none: false
|
130
|
+
requirements:
|
131
|
+
- - ! '>='
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: '0'
|
134
|
+
requirements: []
|
135
|
+
rubyforge_project:
|
136
|
+
rubygems_version: 1.8.24
|
137
|
+
signing_key:
|
138
|
+
specification_version: 3
|
139
|
+
summary: Chain together Sidekiq workers in parallel and/or serial configurations
|
140
|
+
test_files: []
|