backburner 1.3.0 → 1.3.1

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: ba786ac1dbb767afc923b6da0ef80e525043ad20
4
- data.tar.gz: 200863f6e8c0be7731e1448c9c3285db82f3b31f
3
+ metadata.gz: ffcc49440304bb0d25a3710a3d94442fd1881f51
4
+ data.tar.gz: 2e9318efc9a04979135fecc8edfce4e8c8912386
5
5
  SHA512:
6
- metadata.gz: 869c7ec413947f7b58c215aae770aea0826a005b414804d39f356c264df912c41d5ee02f5516d7bd357b937b5d7f48a5d2ac92faa0d450f46ae735bf54217f1b
7
- data.tar.gz: dfcac3547f1a52ea5f6b955a996fd05fa6375b0bef0e9a2b196c363dd913d09885ff998dd4ae54e7305ff8835c9ebd477eac88a2d6ee8a8b0e1fc96953ee87b2
6
+ metadata.gz: caa6aa25343e41b2e8097be38d6b5679f304b9f417f2b0559e085caa2165660fc3ab132f5a920a49360faf16629b84b2d1b740ddf8332b0106df0437458a6f40
7
+ data.tar.gz: 457cb6f9ce73c900e0c54face79f78c8f0f6a89b1462580208f5afa9450f17c717fd7b2dd5701299addb334e260e55baa5c5360583867268c9f4ea921c94e38b
@@ -19,3 +19,4 @@ gemfile: Gemfile
19
19
  notifications:
20
20
  recipients:
21
21
  - nesquena@gmail.com
22
+ - therealdave.myron@gmail.com
@@ -1,6 +1,10 @@
1
1
  # CHANGELOG
2
2
 
3
- ## Version 1.3.0 (February 05 2015)
3
+ ## Version 1.3.1 (April 21 2016)
4
+
5
+ * Addition of thread-pool-based concurrency (@contentfree)
6
+
7
+ ## Version 1.3.0 (February 05 2016)
4
8
 
5
9
  * Enqueue command now responds with beanstalk response details
6
10
 
data/HOOKS.md CHANGED
@@ -5,7 +5,7 @@ In many cases you can use a hook rather than mess around with Backburner's inter
5
5
 
6
6
  ## Job Hooks
7
7
 
8
- Hooks are transparently adapted from [Resque](https://github.com/defunkt/resque/blob/master/docs/HOOKS.md), so
8
+ Hooks are transparently adapted from [Resque](https://github.com/resque/resque/blob/master/docs/HOOKS.md), so
9
9
  if you are familiar with their hook API, now you can use nearly the same ones with beanstalkd and backburner!
10
10
 
11
11
  There are a variety of hooks available that are triggered during the lifecycle of a job:
@@ -56,7 +56,31 @@ class SomeJob
56
56
  end
57
57
  ```
58
58
 
59
- You can also setup modules to create compose-able and reusable hooks for your jobs.
59
+ You can also setup modules to create compose-able and reusable hooks for your jobs. For example:
60
+
61
+ ```ruby
62
+ module LoggedJob
63
+ def before_perform_log_job(*args)
64
+ Logger.info "About to perform #{self} with #{args.inspect}"
65
+ end
66
+ end
67
+
68
+ module BuriedJob
69
+ def on_failure_bury(e, *args)
70
+ Logger.info "Performing #{self} caused an exception (#{e}). Retrying..."
71
+ self.bury
72
+ end
73
+ end
74
+
75
+ class MyJob
76
+ extend LoggedJob
77
+ extend BuriedJob
78
+
79
+ def self.perform(*args)
80
+ # ...
81
+ end
82
+ end
83
+ ```
60
84
 
61
85
  ## Worker Hooks
62
86
 
data/README.md CHANGED
@@ -126,8 +126,8 @@ The key options available are:
126
126
 
127
127
  ## Breaking Changes
128
128
 
129
- Since **v0.4.0**: Jobs used to be placed into default queues based on the name of the class enqueuing i.e NewsletterJob would
130
- be put into a 'newsletter-job' queue. After 0.4.0, all jobs are placed into a primary queue named "my.app.namespace.backburner-jobs"
129
+ Before **v0.4.0**: Jobs were placed into default queues based on the name of the class creating the queue. i.e NewsletterJob would
130
+ be put into a 'newsletter-job' queue. As of 0.4.0, all jobs are placed into a primary queue named "my.app.namespace.backburner-jobs"
131
131
  unless otherwise specified.
132
132
 
133
133
  ## Usage
@@ -402,6 +402,7 @@ By default, Backburner comes with the following workers built-in:
402
402
  | `Backburner::Workers::Simple` | Single threaded, no forking worker. Simplest option. |
403
403
  | `Backburner::Workers::Forking` | Basic forking worker that manages crashes and memory bloat. |
404
404
  | `Backburner::Workers::ThreadsOnFork` | Forking worker that utilizes threads for concurrent processing. |
405
+ | `Backburner::Workers::Threading` | Utilizes thread pools for concurrent processing. |
405
406
 
406
407
  You can select the default worker for processing with:
407
408
 
@@ -423,12 +424,23 @@ or through associated rake tasks with:
423
424
  $ QUEUE=newsletter-sender,push-message THREADS=2 GARBAGE=1000 rake backburner:threads_on_fork:work
424
425
  ```
425
426
 
427
+ When running on MRI or another Ruby implementation with a Global Interpreter Lock (GIL), do not be surprised if you're unable to saturate multiple cores, even with the threads_on_fork worker. To utilize multiple cores, you must run multiple worker processes.
428
+
429
+ Additional concurrency strategies will hopefully be contributed in the future.
430
+ If you are interested in helping out, please let us know.
431
+
432
+ #### More info: Threads on Fork Worker
433
+
426
434
  For more information on the threads_on_fork worker, check out the
427
435
  [ThreadsOnFork Worker](https://github.com/nesquena/backburner/wiki/ThreadsOnFork-worker) documentation. Please note that the `ThreadsOnFork` worker does not work on Windows due to its lack of `fork`.
428
436
 
437
+ #### More info: Threading Worker (thread-pool-based)
429
438
 
430
- Additional workers such as individual `threaded` and `forking` strategies will hopefully be contributed in the future.
431
- If you are interested in helping out, please let us know.
439
+ Configuration options for the Threading worker are similar to the threads_on_fork worker, sans the garbage option. When running via the `backburner` CLI, it's simplest to provide the queue names and maximum number of threads in the format "{queue name}:{max threads in pool}[,{name}:{threads}]":
440
+
441
+ ```
442
+ $ bundle exec backburner -q queue1:4,queue2:4 # and then other options, like environment, pidfile, app root, etc. See docs for the CLI
443
+ ```
432
444
 
433
445
  ### Default Queues
434
446
 
@@ -18,8 +18,10 @@ Gem::Specification.new do |s|
18
18
 
19
19
  s.add_runtime_dependency 'beaneater', '~> 1.0'
20
20
  s.add_runtime_dependency 'dante', '> 0.1.5'
21
+ s.add_runtime_dependency 'concurrent-ruby', '~> 1.0.1'
21
22
 
22
23
  s.add_development_dependency 'rake'
23
24
  s.add_development_dependency 'minitest', '3.2.0'
24
25
  s.add_development_dependency 'mocha'
26
+ s.add_development_dependency 'byebug'
25
27
  end
@@ -13,6 +13,7 @@ require 'backburner/worker'
13
13
  require 'backburner/workers/simple'
14
14
  require 'backburner/workers/forking'
15
15
  require 'backburner/workers/threads_on_fork'
16
+ require 'backburner/workers/threading'
16
17
  require 'backburner/queue'
17
18
 
18
19
  module Backburner
@@ -54,7 +54,7 @@ module Backburner
54
54
  end
55
55
  end
56
56
 
57
- # Returns or assigns queue parallel active jobs limit (only ThreadsOnFork Worker)
57
+ # Returns or assigns queue parallel active jobs limit (only ThreadsOnFork and Threading workers)
58
58
  #
59
59
  # @example
60
60
  # queue_jobs_limit 5
@@ -82,7 +82,7 @@ module Backburner
82
82
  end
83
83
  end
84
84
 
85
- # Returns or assigns queue retry limit (only ThreadsOnFork Worker)
85
+ # Returns or assigns queue retry limit (only ThreadsOnFork worker)
86
86
  #
87
87
  # @example
88
88
  # queue_retry_limit 6
@@ -5,16 +5,14 @@ namespace :backburner do
5
5
  # QUEUE=foo,bar,baz rake backburner:work
6
6
  desc "Start backburner worker using default worker"
7
7
  task :work => :environment do
8
- queues = (ENV["QUEUE"] ? ENV["QUEUE"].split(',') : nil) rescue nil
9
- Backburner.work queues
8
+ Backburner.work get_queues
10
9
  end
11
10
 
12
11
  namespace :simple do
13
12
  # QUEUE=foo,bar,baz rake backburner:simple:work
14
13
  desc "Starts backburner worker using simple processing"
15
14
  task :work => :environment do
16
- queues = (ENV["QUEUE"] ? ENV["QUEUE"].split(',') : nil) rescue nil
17
- Backburner.work queues, :worker => Backburner::Workers::Simple
15
+ Backburner.work get_queues, :worker => Backburner::Workers::Simple
18
16
  end
19
17
  end # simple
20
18
 
@@ -22,8 +20,7 @@ namespace :backburner do
22
20
  # QUEUE=foo,bar,baz rake backburner:forking:work
23
21
  desc "Starts backburner worker using fork processing"
24
22
  task :work => :environment do
25
- queues = (ENV["QUEUE"] ? ENV["QUEUE"].split(',') : nil) rescue nil
26
- Backburner.work queues, :worker => Backburner::Workers::Forking
23
+ Backburner.work get_queues, :worker => Backburner::Workers::Forking
27
24
  end
28
25
  end # forking
29
26
 
@@ -32,12 +29,26 @@ namespace :backburner do
32
29
  # twitter tube will have 10 threads, garbage after 5k executions and retry 5 times.
33
30
  desc "Starts backburner worker using threads_on_fork processing"
34
31
  task :work => :environment do
35
- queues = (ENV["QUEUE"] ? ENV["QUEUE"].split(',') : nil) rescue nil
36
32
  threads = ENV['THREADS'].to_i
37
33
  garbage = ENV['GARBAGE'].to_i
38
34
  Backburner::Workers::ThreadsOnFork.threads_number = threads if threads > 0
39
35
  Backburner::Workers::ThreadsOnFork.garbage_after = garbage if garbage > 0
40
- Backburner.work queues, :worker => Backburner::Workers::ThreadsOnFork
36
+ Backburner.work get_queues, :worker => Backburner::Workers::ThreadsOnFork
41
37
  end
42
38
  end # threads_on_fork
43
- end
39
+
40
+ namespace :threading do
41
+ # QUEUE=twitter:10,parse_page,send_mail,verify_bithday THREADS=2 rake backburner:threading:work
42
+ # twitter tube will have 10 threads
43
+ desc "Starts backburner worker using threading processing"
44
+ task :work => :environment do
45
+ threads = ENV['THREADS'].to_i
46
+ Backburner::Workers::Threading.threads_number = threads if threads > 0
47
+ Backburner.work get_queues, :worker => Backburner::Workers::Threading
48
+ end
49
+ end # threads_on_fork
50
+
51
+ def get_queues
52
+ (ENV["QUEUE"] ? ENV["QUEUE"].split(',') : nil) rescue nil
53
+ end
54
+ end
@@ -1,3 +1,3 @@
1
1
  module Backburner
2
- VERSION = "1.3.0"
2
+ VERSION = "1.3.1"
3
3
  end
@@ -0,0 +1,129 @@
1
+ require 'concurrent'
2
+
3
+ module Backburner
4
+ module Workers
5
+ class Threading < Worker
6
+ class << self
7
+ attr_accessor :shutdown
8
+ attr_accessor :threads_number
9
+ end
10
+
11
+ # Custom initializer just to set @tubes_data
12
+ def initialize(*args)
13
+ @tubes_data = {}
14
+ super
15
+ self.process_tube_options
16
+ end
17
+
18
+ # Used to prepare job queues before processing jobs.
19
+ # Setup beanstalk tube_names and watch all specified tubes for jobs.
20
+ #
21
+ # @raise [Beaneater::NotConnected] If beanstalk fails to connect.
22
+ # @example
23
+ # @worker.prepare
24
+ #
25
+ def prepare
26
+ self.tube_names.map! { |name| expand_tube_name(name) }.uniq!
27
+ log_info "Working #{tube_names.size} queues: [ #{tube_names.join(', ')} ]"
28
+ @thread_pools = {}
29
+ @tubes_data.each do |name, config|
30
+ max_threads = (config[:threads] || self.class.threads_number || ::Concurrent.processor_count).to_i
31
+ @thread_pools[name] = (::Concurrent::ThreadPoolExecutor.new(min_threads: 1, max_threads: max_threads))
32
+ end
33
+ end
34
+
35
+ # Starts processing new jobs indefinitely.
36
+ # Primary way to consume and process jobs in specified tubes.
37
+ #
38
+ # @example
39
+ # @worker.start
40
+ #
41
+ def start(wait=true)
42
+ prepare
43
+
44
+ @thread_pools.each do |tube_name, pool|
45
+ pool.max_length.times do
46
+ # Create a new connection and set it up to listen on this tube name
47
+ connection = new_connection.tap{ |conn| conn.tubes.watch!(tube_name) }
48
+ connection.on_reconnect = lambda { |conn| conn.tubes.watch!(tube_name) }
49
+
50
+ # Make it work jobs using its own connection per thread
51
+ pool.post(connection) { |connection|
52
+ loop {
53
+ begin
54
+ work_one_job(connection)
55
+
56
+ rescue => e
57
+ log_error("Exception caught in thread pool loop. Continuing. -> #{e.message}\nBacktrace: #{e.backtrace}")
58
+ end
59
+ }
60
+ }
61
+ end
62
+ end
63
+
64
+ wait_for_shutdown! if wait
65
+ end
66
+
67
+ # FIXME: We can't use this on_reconnect method since we don't know which thread
68
+ # pool the connection belongs to (and therefore we can't re-watch the right tubes).
69
+ # However, we set the individual connections' on_reconnect method in #start
70
+ # def on_reconnect(conn)
71
+ # watch_tube(@watching_tube, conn) if @watching_tube
72
+ # end
73
+
74
+ # Process the special tube_names of Threading worker:
75
+ # The format is tube_name:custom_threads_limit
76
+ #
77
+ # @example
78
+ # process_tube_names(['foo:10', 'lol'])
79
+ # => ['foo', lol']
80
+ def process_tube_names(tube_names)
81
+ names = compact_tube_names(tube_names)
82
+ if names.nil?
83
+ nil
84
+ else
85
+ names.map do |name|
86
+ data = name.split(":")
87
+ tube_name = data.first
88
+ threads_number = data[1].empty? ? nil : data[1].to_i rescue nil
89
+ @tubes_data[expand_tube_name(tube_name)] = {
90
+ :threads => threads_number
91
+ }
92
+ tube_name
93
+ end
94
+ end
95
+ end
96
+
97
+ # Process the tube settings
98
+ # This overrides @tubes_data set by process_tube_names method. So a tube has name 'super_job:5'
99
+ # and the tube class has setting queue_jobs_limit 10, the result limit will be 10
100
+ # If the tube is known by existing beanstalkd queue, but not by class - skip it
101
+ #
102
+ def process_tube_options
103
+ Backburner::Worker.known_queue_classes.each do |queue|
104
+ next if @tubes_data[expand_tube_name(queue)].nil?
105
+ queue_settings = {
106
+ :threads => queue.queue_jobs_limit
107
+ }
108
+ @tubes_data[expand_tube_name(queue)].merge!(queue_settings){|k, v1, v2| v2.nil? ? v1 : v2 }
109
+ end
110
+ end
111
+
112
+ # Wait for the shutdown signel
113
+ def wait_for_shutdown!
114
+ while !self.class.shutdown do
115
+ sleep 0.5
116
+ end
117
+
118
+ # Shutting down
119
+ # FIXME: Shut down each thread's connection
120
+ @thread_pools.each { |name, pool| pool.kill }
121
+ end
122
+
123
+ def shutdown
124
+ Backburner::Workers::Threading.shutdown = true
125
+ super
126
+ end
127
+ end # Threading
128
+ end # Workers
129
+ end # Backburner
@@ -69,7 +69,6 @@ module Backburner
69
69
  # Custom initializer just to set @tubes_data
70
70
  def initialize(*args)
71
71
  @tubes_data = {}
72
- @mutex = Mutex.new
73
72
  super
74
73
  self.process_tube_options
75
74
  end
@@ -2,7 +2,7 @@ require File.expand_path('../../test_helper', __FILE__)
2
2
  require File.expand_path('../../fixtures/test_jobs', __FILE__)
3
3
  require File.expand_path('../../fixtures/hooked', __FILE__)
4
4
 
5
- describe "Backburner::Workers::Basic module" do
5
+ describe "Backburner::Workers::Simple module" do
6
6
  before do
7
7
  Backburner.default_queues.clear
8
8
  @worker_class = Backburner::Workers::Simple
@@ -0,0 +1,68 @@
1
+ require File.expand_path('../../test_helper', __FILE__)
2
+ require File.expand_path('../../fixtures/test_jobs', __FILE__)
3
+ require File.expand_path('../../fixtures/hooked', __FILE__)
4
+
5
+ describe "Backburner::Workers::Threading worker" do
6
+ before do
7
+ Backburner.default_queues.clear
8
+ @worker_class = Backburner::Workers::Threading
9
+ end
10
+
11
+ describe "for prepare method" do
12
+ it "should make tube names array always unique to avoid duplication" do
13
+ worker = @worker_class.new(["foo", "demo.test.foo"])
14
+ worker.prepare
15
+ assert_equal ["demo.test.foo"], worker.tube_names
16
+ end
17
+
18
+ it 'creates a thread pool per queue' do
19
+ worker = @worker_class.new(%w(foo bar))
20
+ out = capture_stdout { worker.prepare }
21
+ assert_equal 2, worker.instance_variable_get("@thread_pools").keys.size
22
+ end
23
+
24
+ it 'uses Concurrent.processor_count if no custom thread count is provided' do
25
+ worker = @worker_class.new("foo")
26
+ out = capture_stdout { worker.prepare }
27
+ assert_equal ::Concurrent.processor_count, worker.instance_variable_get("@thread_pools")["demo.test.foo"].max_length
28
+ end
29
+ end # prepare
30
+
31
+ describe "for process_tube_names method" do
32
+ it "should interpret the job_name:threads_limit format" do
33
+ worker = @worker_class.new(["foo:4"])
34
+ assert_equal ["foo"], worker.tube_names
35
+ end
36
+
37
+ it "should interpret correctly even if missing values" do
38
+ tubes = %W(foo1:2 foo2)
39
+ worker = @worker_class.new(tubes)
40
+ assert_equal %W(foo1 foo2), worker.tube_names
41
+ end
42
+
43
+ it "should store interpreted values correctly" do
44
+ tubes = %W(foo1 foo2:2)
45
+ worker = @worker_class.new(tubes)
46
+ assert_equal({
47
+ "demo.test.foo1" => { :threads => nil },
48
+ "demo.test.foo2" => { :threads => 2 }
49
+ }, worker.instance_variable_get("@tubes_data"))
50
+ end
51
+ end # process_tube_names
52
+
53
+ describe 'working a queue' do
54
+ before do
55
+ @worker = @worker_class.new(["foo:3"])
56
+ capture_stdout { @worker.prepare }
57
+ end
58
+
59
+ it 'runs work_on_job per thread' do
60
+ clear_jobs!("foo")
61
+ job_count=10
62
+ job_count.times { @worker_class.enqueue TestJob, [1, 0], :queue => "foo" } # TestJob adds the given arguments together and then to $worker_test_count
63
+ @worker.start(false) # don't wait for shutdown
64
+ sleep 0.5 # Wait for threads to do their work
65
+ assert_equal job_count, $worker_test_count
66
+ end
67
+ end # working a queue
68
+ end
metadata CHANGED
@@ -1,55 +1,69 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: backburner
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.0
4
+ version: 1.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nathan Esquenazi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-02-05 00:00:00.000000000 Z
11
+ date: 2016-10-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: beaneater
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ~>
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
19
  version: '1.0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ~>
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '1.0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: dante
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - '>'
31
+ - - ">"
32
32
  - !ruby/object:Gem::Version
33
33
  version: 0.1.5
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
40
  version: 0.1.5
41
+ - !ruby/object:Gem::Dependency
42
+ name: concurrent-ruby
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 1.0.1
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 1.0.1
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: rake
43
57
  requirement: !ruby/object:Gem::Requirement
44
58
  requirements:
45
- - - '>='
59
+ - - ">="
46
60
  - !ruby/object:Gem::Version
47
61
  version: '0'
48
62
  type: :development
49
63
  prerelease: false
50
64
  version_requirements: !ruby/object:Gem::Requirement
51
65
  requirements:
52
- - - '>='
66
+ - - ">="
53
67
  - !ruby/object:Gem::Version
54
68
  version: '0'
55
69
  - !ruby/object:Gem::Dependency
@@ -70,14 +84,28 @@ dependencies:
70
84
  name: mocha
71
85
  requirement: !ruby/object:Gem::Requirement
72
86
  requirements:
73
- - - '>='
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: byebug
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
74
102
  - !ruby/object:Gem::Version
75
103
  version: '0'
76
104
  type: :development
77
105
  prerelease: false
78
106
  version_requirements: !ruby/object:Gem::Requirement
79
107
  requirements:
80
- - - '>='
108
+ - - ">="
81
109
  - !ruby/object:Gem::Version
82
110
  version: '0'
83
111
  description: Beanstalk background job processing made easy
@@ -88,8 +116,8 @@ executables:
88
116
  extensions: []
89
117
  extra_rdoc_files: []
90
118
  files:
91
- - .gitignore
92
- - .travis.yml
119
+ - ".gitignore"
120
+ - ".travis.yml"
93
121
  - CHANGELOG.md
94
122
  - CONTRIBUTING.md
95
123
  - Gemfile
@@ -124,6 +152,7 @@ files:
124
152
  - lib/backburner/worker.rb
125
153
  - lib/backburner/workers/forking.rb
126
154
  - lib/backburner/workers/simple.rb
155
+ - lib/backburner/workers/threading.rb
127
156
  - lib/backburner/workers/threads_on_fork.rb
128
157
  - test/async_proxy_test.rb
129
158
  - test/back_burner_test.rb
@@ -144,6 +173,7 @@ files:
144
173
  - test/worker_test.rb
145
174
  - test/workers/forking_worker_test.rb
146
175
  - test/workers/simple_worker_test.rb
176
+ - test/workers/threading_worker_test.rb
147
177
  - test/workers/threads_on_fork_worker_test.rb
148
178
  homepage: http://github.com/nesquena/backburner
149
179
  licenses:
@@ -155,12 +185,12 @@ require_paths:
155
185
  - lib
156
186
  required_ruby_version: !ruby/object:Gem::Requirement
157
187
  requirements:
158
- - - '>='
188
+ - - ">="
159
189
  - !ruby/object:Gem::Version
160
190
  version: '0'
161
191
  required_rubygems_version: !ruby/object:Gem::Requirement
162
192
  requirements:
163
- - - '>='
193
+ - - ">="
164
194
  - !ruby/object:Gem::Version
165
195
  version: '0'
166
196
  requirements: []
@@ -189,4 +219,5 @@ test_files:
189
219
  - test/worker_test.rb
190
220
  - test/workers/forking_worker_test.rb
191
221
  - test/workers/simple_worker_test.rb
222
+ - test/workers/threading_worker_test.rb
192
223
  - test/workers/threads_on_fork_worker_test.rb