threasy 0.4.1 → 0.5.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: b1bc950437e631aa8c150efa45db53103b63c72a
4
- data.tar.gz: 3b9635b78869d69cb260f77cf63242055b3effab
3
+ metadata.gz: 11e5f8c6348eca49829c58687a62ce48a414b97c
4
+ data.tar.gz: 94b1c10c04d5a9ec92e66d592c8ab694d4ddc625
5
5
  SHA512:
6
- metadata.gz: 45c57665f96db2520e878aa5e43145ee16f0f6165109c2e8ffcc5a181e82bf7cdda02aae55c24fd47ad15c19698f944a51fd10f1caa8069b47e0d03af860b60b
7
- data.tar.gz: 09223ebffbaccd54f059ab5dce971fd96c03fecf9f31d5cdf67890aa720f5e12524e16d8fb819a202d545b74822cdb07407fb4b9134e149b406a43f6a148ed52
6
+ metadata.gz: 1523591989b79b83ea7e94eeb158d365b80ffb6fbb32d2ac4ee5109414b9124fa49862f1d9b0b860c63d704b277f31432f37327b4957ae14a71b9404f0ce2b8e
7
+ data.tar.gz: 36e4ff11898c517f8f5196d011dc1538bd8d405933446d955d36a67a31034d9bdc968ff7ae64b939324dd4005545db7bbc65b96d8099f1274813b920de70e589
data/README.md CHANGED
@@ -3,15 +3,15 @@
3
3
  [travis-image]: https://secure.travis-ci.org/carlzulauf/threasy.png?branch=master
4
4
  [travis-link]: http://travis-ci.org/carlzulauf/threasy
5
5
 
6
- Dead simple in-process threaded background job solution.
6
+ **Thr**eaded, **easy** to use scheduling and background job solution.
7
7
 
8
- Includes scheduling for jobs in the future and/or recurring jobs.
8
+ Schedules are managed by a watcher thread and enqueued as background jobs when they are due.
9
9
 
10
- Work waiting to be processed is stored in a thread-safe `Queue` and worked on by a small pool of worker threads.
10
+ Background work is stored in a thread-safe `Queue` and worked on by a pool of worker threads.
11
11
 
12
12
  ### What to expect
13
13
 
14
- * Dead simple-ness
14
+ * Simple API
15
15
  * Ability to queue or schedule ruby blocks for asynchronus execution
16
16
  * Extremely light-weight
17
17
  * No dependencies (outside ruby stdlib)
@@ -45,7 +45,7 @@ Or install it yourself as:
45
45
 
46
46
  ## Usage
47
47
 
48
- ### `enqueue`
48
+ ### `Threasy.enqueue`
49
49
 
50
50
  ```ruby
51
51
  # Use a block
@@ -57,7 +57,7 @@ Threasy.enqueue MyJob.new(1,2,3)
57
57
 
58
58
  Jobs are placed in a work queue. Worker threads are spun up to process jobs as the queue grows.
59
59
 
60
- ### `schedule`
60
+ ### `Threasy.schedule`
61
61
 
62
62
  Puts a job onto the schedule. Once the scheduler sees a job is due for processessing, it is enqueued into the work queue to be processed like any other job.
63
63
 
@@ -66,6 +66,7 @@ Available options:
66
66
  * `:every`: number of seconds between repetition. Can be combined with `:at` or `:in`.
67
67
  * `:in`: number of seconds until job is (next) triggered.
68
68
  * `:at`: `Time` job is (next) triggered.
69
+ * `:times`: number of times to trigger job before removing it from the schedule.
69
70
 
70
71
  Example:
71
72
 
@@ -77,15 +78,15 @@ Threasy.schedule(:in => 5.minutes) { puts "In the background, 5 minutes from now
77
78
  Threasy.schedule(MyJob.new(1,2,3), every: 5.minutes)
78
79
  ```
79
80
 
80
- ### `schedules`
81
+ ### `Threasy.schedules`
81
82
 
82
83
  Returns the default instance of [`Threasy::Schedule`][schedule], which manages scheduled jobs.
83
84
 
84
- ### `work`
85
+ ### `Threasy.work`
85
86
 
86
87
  Returns the default instance of [`Threasy::Work`][work], which manages the work queue and worker threads.
87
88
 
88
- ### `config`
89
+ ### `Threasy.config`
89
90
 
90
91
  Returns the default instance of [`Threasy::Config`][config], which manages runtime configuration options.
91
92
 
@@ -1,9 +1,11 @@
1
1
  module Threasy
2
2
  class Config
3
- attr_accessor :work, :schedule, :max_workers, :max_sleep, :max_overdue
3
+ attr_accessor :work, :schedule
4
+ attr_accessor :min_workers, :max_workers, :max_sleep, :max_overdue
4
5
  attr_writer :logger
5
6
 
6
7
  def initialize
8
+ self.min_workers = 1
7
9
  self.max_workers = 4
8
10
  self.max_sleep = 60.0
9
11
  self.max_overdue = 300.0
@@ -11,7 +11,7 @@ module Threasy
11
11
  # and should not be created by hand.
12
12
  #
13
13
  # See `Threasy::Schedule#add`
14
- attr_accessor :schedule, :work, :job, :at, :repeat, :times
14
+ attr_accessor :schedule, :work, :job, :args, :at, :repeat, :times
15
15
 
16
16
  def initialize(job, options = {})
17
17
  self.schedule = options.fetch(:schedule) { Threasy.schedules }
@@ -21,6 +21,7 @@ module Threasy
21
21
  seconds = options.fetch(:in) { repeat || 60 }
22
22
  self.at = options.fetch(:at) { Time.now + seconds }
23
23
  self.times = options[:times]
24
+ self.args = options.fetch(:args) { [] }
24
25
  end
25
26
 
26
27
  def repeat?
@@ -49,7 +50,7 @@ module Threasy
49
50
 
50
51
  def work!
51
52
  if once? || overdue < max_overdue
52
- work.enqueue(job) if times_remaining?
53
+ work.enqueue(job, *args) if times_remaining?
53
54
  self.times -= 1 unless times.nil?
54
55
  end
55
56
 
@@ -1,3 +1,3 @@
1
1
  module Threasy
2
- VERSION = "0.4.1"
2
+ VERSION = "0.5.0"
3
3
  end
@@ -19,6 +19,7 @@ module Threasy
19
19
  @queue = TimeoutQueue.new
20
20
  @pool = Set.new
21
21
  @semaphore = Mutex.new
22
+ min_workers.times { add_worker }
22
23
  end
23
24
 
24
25
  # Enqueue a job into the work queue
@@ -36,8 +37,9 @@ module Threasy
36
37
  # # Enqueue string that evals to a job object
37
38
  # Threasy.enqueue("BackgroundJob.new")
38
39
  #
39
- def enqueue(job = nil, &block)
40
- queue.push(block_given? ? block : job).tap { check_workers }
40
+ def enqueue(*args, &block)
41
+ args.unshift(block) if block_given?
42
+ queue.push(args).tap { check_workers }
41
43
  end
42
44
 
43
45
  alias_method :enqueue_block, :enqueue
@@ -50,6 +52,10 @@ module Threasy
50
52
  queue.pop
51
53
  end
52
54
 
55
+ def min_workers
56
+ Threasy.config.min_workers
57
+ end
58
+
53
59
  def max_workers
54
60
  Threasy.config.max_workers
55
61
  end
@@ -57,17 +63,16 @@ module Threasy
57
63
  def check_workers
58
64
  sync do
59
65
  pool_size = pool.size
60
- queue_size = queue.size
61
- log "Checking workers. Pool: #{pool_size}, Max: #{max_workers}, Queue: #{queue_size}"
66
+ log "Checking workers. Pool: #{pool_size} (min: #{min_workers}, max: #{max_workers})"
62
67
  if pool_size < max_workers
63
- add_worker(pool_size) if pool_size == 0 || queue_size > max_workers
68
+ add_worker if pool_size == 0 || queue.size > max_workers
64
69
  end
65
70
  end
66
71
  end
67
72
 
68
- def add_worker(size)
73
+ def add_worker
69
74
  log "Adding new worker to pool"
70
- worker = Worker.new(self, size)
75
+ worker = Worker.new(self, pool.size)
71
76
  pool.add worker
72
77
  worker.work
73
78
  end
@@ -87,18 +92,22 @@ module Threasy
87
92
  end
88
93
 
89
94
  def work
90
- Thread.start do
91
- while job = @work.grab
92
- log.debug "Worker ##{@id} has grabbed a job"
93
- begin
94
- job = eval(job) if job.kind_of?(String)
95
- job.respond_to?(:perform) ? job.perform : job.call
96
- rescue Exception => e
97
- log.error %|Worker ##{@id} error: #{e.message}\n#{e.backtrace.join("\n")}|
95
+ @thread = Thread.start do
96
+ loop do
97
+ if args = @work.grab
98
+ job = args.shift
99
+ log.debug "Worker ##{@id} has grabbed a job"
100
+ begin
101
+ job = eval(job) if job.kind_of?(String)
102
+ job.respond_to?(:perform) ? job.perform(*args) : job.call(*args)
103
+ rescue Exception => e
104
+ log.error %|Worker ##{@id} error: #{e.message}\n#{e.backtrace.join("\n")}|
105
+ end
106
+ elsif @work.pool.size > @work.min_workers
107
+ @work.sync { @work.pool.delete self }
108
+ break
98
109
  end
99
110
  end
100
- log.debug "Worker ##{@id} removing self from pool"
101
- @work.sync{ @work.pool.delete self }
102
111
  end
103
112
  end
104
113
 
@@ -36,6 +36,16 @@ describe "Threasy::Schedule" do
36
36
  expect(subject).not_to receive(:add_entry)
37
37
  subject.add(job, at: Time.now - 100)
38
38
  end
39
+
40
+ it "should pass optional arguments onto job when its worked" do
41
+ async do |done|
42
+ args = [:foo, :bar]
43
+ subject.add(in: 0.01, args: args) do |*a|
44
+ expect(a).to eq(args)
45
+ done.()
46
+ end
47
+ end
48
+ end
39
49
  end
40
50
 
41
51
  describe "#remove" do
@@ -3,7 +3,7 @@ class TestJob
3
3
  @resolver = resolver
4
4
  end
5
5
 
6
- def perform
6
+ def perform(*args)
7
7
  @resolver.()
8
8
  end
9
9
  end
@@ -36,5 +36,16 @@ describe "Threasy::Work" do
36
36
  subject.enqueue { done.() }
37
37
  end
38
38
  end
39
+
40
+ it "should pass optional arguments onto job" do
41
+ async do |done|
42
+ args = [:foo, :bar]
43
+ job = proc do |*a|
44
+ expect(a).to eq(args)
45
+ done.()
46
+ end
47
+ subject.enqueue job, *args
48
+ end
49
+ end
39
50
  end
40
51
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: threasy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.1
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Carl Zulauf
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-08-29 00:00:00.000000000 Z
11
+ date: 2015-09-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler