sidekiq-superworker 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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)
|
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)
|
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: []
|