threasy 0.4.1 → 0.5.0

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.
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