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 +4 -4
- data/README.md +10 -9
- data/lib/threasy/config.rb +3 -1
- data/lib/threasy/schedule/entry.rb +3 -2
- data/lib/threasy/version.rb +1 -1
- data/lib/threasy/work.rb +26 -17
- data/spec/threasy/schedule_spec.rb +10 -0
- data/spec/threasy/work_spec.rb +12 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 11e5f8c6348eca49829c58687a62ce48a414b97c
|
4
|
+
data.tar.gz: 94b1c10c04d5a9ec92e66d592c8ab694d4ddc625
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
6
|
+
**Thr**eaded, **easy** to use scheduling and background job solution.
|
7
7
|
|
8
|
-
|
8
|
+
Schedules are managed by a watcher thread and enqueued as background jobs when they are due.
|
9
9
|
|
10
|
-
|
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
|
-
*
|
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
|
|
data/lib/threasy/config.rb
CHANGED
@@ -1,9 +1,11 @@
|
|
1
1
|
module Threasy
|
2
2
|
class Config
|
3
|
-
attr_accessor :work, :schedule
|
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
|
|
data/lib/threasy/version.rb
CHANGED
data/lib/threasy/work.rb
CHANGED
@@ -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(
|
40
|
-
|
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
|
-
|
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
|
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
|
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
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
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
|
data/spec/threasy/work_spec.rb
CHANGED
@@ -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
|
+
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-
|
11
|
+
date: 2015-09-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|