threasy 0.3.0 → 0.3.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/threasy/schedule/entry.rb +11 -0
- data/lib/threasy/schedule.rb +65 -1
- data/lib/threasy/version.rb +1 -1
- data/lib/threasy/work.rb +32 -6
- data/lib/threasy.rb +71 -0
- data/spec/spec_helper.rb +2 -3
- data/spec/threasy/schedule_spec.rb +10 -0
- 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: 24769445131b62b227817a4cd7eacf4682e3855e
|
4
|
+
data.tar.gz: f5d317aee9b0de3f7b4989526b8716738f9f45fb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a2b47d68b23493aa3a66e6ef6a5369c06d5301a07cb952a9a1b77f322991176f7d4052ec9dd97f533be0fb31391460fce429d6cdda3abf95be8e7b84db728c6e
|
7
|
+
data.tar.gz: db3c0cebce5e18bc13854112782d91c273c34f3a14c0e6b1a9a2c94360f6b0d6ecd4e5e2173bf8fa30ca8bc2e514a3292ce6fbfcfd0d80b2700d6f12d4440cc9
|
@@ -1,5 +1,16 @@
|
|
1
1
|
module Threasy
|
2
2
|
class Schedule::Entry
|
3
|
+
# = Schedule Entry
|
4
|
+
#
|
5
|
+
# Represents a single entry in a schedule.
|
6
|
+
#
|
7
|
+
# Class is responsible for keeping track of the timing and recurrance of
|
8
|
+
# a the supplied `job` object.
|
9
|
+
#
|
10
|
+
# Entry instances are usually created by a `Threasy::Schedule` instance
|
11
|
+
# and should not be created by hand.
|
12
|
+
#
|
13
|
+
# See `Threasy::Schedule#add`
|
3
14
|
attr_accessor :schedule, :work, :job, :at, :repeat
|
4
15
|
|
5
16
|
def initialize(job, options = {})
|
data/lib/threasy/schedule.rb
CHANGED
@@ -1,9 +1,35 @@
|
|
1
1
|
module Threasy
|
2
2
|
class Schedule
|
3
|
+
# = Threasy::Schedule
|
4
|
+
#
|
5
|
+
# Class that manages a "schedule".
|
6
|
+
#
|
7
|
+
# A "schedule" is a collection of jobs, some one-time, some repeating,
|
8
|
+
# that execute at specific times.
|
9
|
+
#
|
10
|
+
# `Threasy::Schedule` maintains an ordered list of jobs, sorted by which
|
11
|
+
# jobs are up "next".
|
12
|
+
#
|
13
|
+
# The `watcher` thread periodically wakes up, finds jobs that need to be
|
14
|
+
# worked, and enqueues them into the `work` queue.
|
15
|
+
#
|
16
|
+
# The `work` queue defaults to the default `Threasy::Work` instance, but
|
17
|
+
# can be any object that responds to `enqueue` and accepts your job objects.
|
18
|
+
#
|
19
|
+
# == Example
|
20
|
+
#
|
21
|
+
# schedule = Threasy::Schedule.new
|
22
|
+
# schedule.add(MyJob.new(1,2,3), in: 1.hour, every: 0.5.days)
|
3
23
|
include Enumerable
|
4
24
|
|
5
25
|
attr_reader :schedules, :watcher
|
6
26
|
|
27
|
+
# Creates new `Threasy::Schedule` instance
|
28
|
+
#
|
29
|
+
# === Parameters
|
30
|
+
#
|
31
|
+
# * `work` - Optional. Usually a `Threasy::Work` instance.
|
32
|
+
# Defaults to `Threasy.work`
|
7
33
|
def initialize(work = nil)
|
8
34
|
@work = work
|
9
35
|
@semaphore = Mutex.new
|
@@ -11,12 +37,44 @@ module Threasy
|
|
11
37
|
@watcher = Thread.new{ watch }
|
12
38
|
end
|
13
39
|
|
40
|
+
# Schedule a job
|
41
|
+
#
|
42
|
+
# === Examples
|
43
|
+
#
|
44
|
+
# schedule = Threasy::Schedule.new(work: Threasy::Work.new)
|
45
|
+
#
|
46
|
+
# # Schedule blocks
|
47
|
+
# schedule.add(in: 5.min) { do_some_background_work }
|
48
|
+
#
|
49
|
+
# # Schedule job objects compatible with the `work` queue
|
50
|
+
# schedule.add(BackgroundJob.new(some: data), every: 1.hour)
|
51
|
+
#
|
52
|
+
# # Enqueue strings that can be evals to a job object
|
53
|
+
# schedule.add("BackgroundJob.new", every: 1.day)
|
54
|
+
#
|
55
|
+
# === Parameters
|
56
|
+
#
|
57
|
+
# * `job` - Job object which responds to `perform` or `call`
|
58
|
+
# * `options`
|
59
|
+
# * `every: n` - If present, job is repeated every `n` seconds
|
60
|
+
# * `in: n` - `n` seconds until job is executed
|
61
|
+
# * `at: Time` - Time to execute job at
|
62
|
+
# * `&block` - Job block
|
63
|
+
#
|
64
|
+
# Must have either a `job` object or job `&block` present.
|
65
|
+
#
|
66
|
+
# === Returns
|
67
|
+
#
|
68
|
+
# * `Threasy::Schedule::Entry` if job was successfully added to schedule
|
69
|
+
# * `nil` if job was for the past
|
14
70
|
def add(*args, &block)
|
15
71
|
options = args.last.is_a?(Hash) ? args.pop : {}
|
16
72
|
job = block_given? ? block : args.first
|
17
|
-
|
73
|
+
entry = Entry.new job, {schedule: self}.merge(options)
|
74
|
+
add_entry entry if entry.future?
|
18
75
|
end
|
19
76
|
|
77
|
+
# Add a `Threasy::Schedule::Entry` object to `schedules`
|
20
78
|
def add_entry(entry)
|
21
79
|
sync do
|
22
80
|
schedules << entry
|
@@ -26,6 +84,7 @@ module Threasy
|
|
26
84
|
entry
|
27
85
|
end
|
28
86
|
|
87
|
+
# Returns the current work queue
|
29
88
|
def work
|
30
89
|
@work ||= Threasy.work
|
31
90
|
end
|
@@ -34,6 +93,7 @@ module Threasy
|
|
34
93
|
sync { schedules.delete entry }
|
35
94
|
end
|
36
95
|
|
96
|
+
# Wakes up the watcher thread if its sleeping
|
37
97
|
def tickle_watcher
|
38
98
|
watcher.wakeup if watcher.stop?
|
39
99
|
end
|
@@ -51,6 +111,9 @@ module Threasy
|
|
51
111
|
sync { schedules.clear }
|
52
112
|
end
|
53
113
|
|
114
|
+
# Used by the watcher thread to find jobs that are due, add them to the
|
115
|
+
# `work` queue, re-sort the schedule, and attempt to sleep until the next
|
116
|
+
# job is due.
|
54
117
|
def watch
|
55
118
|
loop do
|
56
119
|
Thread.stop if schedules.empty?
|
@@ -68,6 +131,7 @@ module Threasy
|
|
68
131
|
end
|
69
132
|
end
|
70
133
|
|
134
|
+
# Pop entries off the schedule that are due
|
71
135
|
def entries_due
|
72
136
|
[].tap do |entries|
|
73
137
|
sync do
|
data/lib/threasy/version.rb
CHANGED
data/lib/threasy/work.rb
CHANGED
@@ -1,5 +1,18 @@
|
|
1
1
|
module Threasy
|
2
2
|
class Work
|
3
|
+
# = Threasy::Work
|
4
|
+
#
|
5
|
+
# Class to manage the work queue.
|
6
|
+
#
|
7
|
+
# An instance of `Threasy::Work` will manage a pool of worker threads and
|
8
|
+
# a queue of jobs. As the job queue grows, new worker threads are created
|
9
|
+
# process the jobs. When the Queue remains empty, worker threads are culled.
|
10
|
+
#
|
11
|
+
# == Example
|
12
|
+
#
|
13
|
+
# work = Threasy::Work.new
|
14
|
+
# work.enqueue { puts "Hello from the background!" }
|
15
|
+
# # Outputs: Hello from the background!
|
3
16
|
attr_reader :queue, :pool
|
4
17
|
|
5
18
|
def initialize
|
@@ -8,8 +21,23 @@ module Threasy
|
|
8
21
|
@semaphore = Mutex.new
|
9
22
|
end
|
10
23
|
|
24
|
+
# Enqueue a job into the work queue
|
25
|
+
#
|
26
|
+
# === Examples
|
27
|
+
#
|
28
|
+
# work = Threasy::Work.new
|
29
|
+
#
|
30
|
+
# # Enqueue blocks
|
31
|
+
# work.enqueue { do_some_background_work }
|
32
|
+
#
|
33
|
+
# # Enqueue job objects that respond to `perform` or `call`
|
34
|
+
# work.enqueue BackgroundJob.new(some: data)
|
35
|
+
#
|
36
|
+
# # Enqueue string that evals to a job object
|
37
|
+
# Threasy.enqueue("BackgroundJob.new")
|
38
|
+
#
|
11
39
|
def enqueue(job = nil, &block)
|
12
|
-
queue.push(block_given? ? block : job).tap{ check_workers }
|
40
|
+
queue.push(block_given? ? block : job).tap { check_workers }
|
13
41
|
end
|
14
42
|
|
15
43
|
alias_method :enqueue_block, :enqueue
|
@@ -38,11 +66,9 @@ module Threasy
|
|
38
66
|
end
|
39
67
|
|
40
68
|
def add_worker(size)
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
pool.add worker
|
45
|
-
# end
|
69
|
+
log "Adding new worker to pool"
|
70
|
+
worker = Worker.new(self, size)
|
71
|
+
pool.add worker
|
46
72
|
worker.work
|
47
73
|
end
|
48
74
|
|
data/lib/threasy.rb
CHANGED
@@ -1,4 +1,7 @@
|
|
1
1
|
require "logger"
|
2
|
+
require "thread"
|
3
|
+
require "timeout"
|
4
|
+
require "set"
|
2
5
|
|
3
6
|
require "threasy/version"
|
4
7
|
require "threasy/config"
|
@@ -7,28 +10,96 @@ require "threasy/schedule"
|
|
7
10
|
require "threasy/schedule/entry"
|
8
11
|
|
9
12
|
module Threasy
|
13
|
+
# Returns default instance of `Threasy::Config`.
|
14
|
+
#
|
15
|
+
# Can be used with a block for changing multiple configs.
|
16
|
+
#
|
17
|
+
# Threasy.config do |c|
|
18
|
+
# c.max_sleep = 10.minutes
|
19
|
+
# c.max_overdue = 1.hour
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# ==== Parameters
|
23
|
+
#
|
24
|
+
# * `&block` - Optional block that will be yielded the config object
|
25
|
+
#
|
26
|
+
# ==== Returns
|
27
|
+
#
|
28
|
+
# * `Threasy::Config` instance
|
10
29
|
def self.config
|
11
30
|
@@config ||= Config.new
|
12
31
|
yield @@config if block_given?
|
13
32
|
@@config
|
14
33
|
end
|
15
34
|
|
35
|
+
# Shortcut for `Threasy::Config#logger`
|
16
36
|
def self.logger
|
17
37
|
config.logger
|
18
38
|
end
|
19
39
|
|
40
|
+
# Shortcut for default `Threasy::Work` instance.
|
41
|
+
#
|
42
|
+
# === Returns
|
43
|
+
#
|
44
|
+
# * `Threasy::Work` instance
|
20
45
|
def self.work
|
21
46
|
config.work ||= Work.new
|
22
47
|
end
|
23
48
|
|
49
|
+
# Shortcut to enqueue work into default `Threasy::Work` instance.
|
50
|
+
#
|
51
|
+
# === Examples
|
52
|
+
#
|
53
|
+
# # Enqueue blocks
|
54
|
+
# Threasy.enqueue { do_some_background_work }
|
55
|
+
#
|
56
|
+
# # Enqueue objects that respond to `perform` or `call`
|
57
|
+
# Threasy.enqueue BackgroundJob.new(some: data)
|
58
|
+
#
|
59
|
+
# # Enqueue strings that can be evals to an object
|
60
|
+
# Threasy.enqueue("BackgroundJob.new")
|
61
|
+
#
|
24
62
|
def self.enqueue(*args, &block)
|
25
63
|
work.enqueue *args, &block
|
26
64
|
end
|
27
65
|
|
66
|
+
# Shortcut for default `Threasy::Schedule` instance.
|
67
|
+
#
|
68
|
+
# === Returns
|
69
|
+
#
|
70
|
+
# * `Threasy::Schedule` instance
|
28
71
|
def self.schedules
|
29
72
|
config.schedule ||= Schedule.new(work)
|
30
73
|
end
|
31
74
|
|
75
|
+
# Shortcut to schedule work with the default `Threasy::Schedule` instance.
|
76
|
+
#
|
77
|
+
# === Examples
|
78
|
+
#
|
79
|
+
# # Schedule blocks
|
80
|
+
# Threasy.schedule(in: 5.min) { do_some_background_work }
|
81
|
+
#
|
82
|
+
# # Schedule job objects that respond to `perform` or `call`
|
83
|
+
# Threasy.schedule(BackgroundJob.new(some: data), every: 1.hour)
|
84
|
+
#
|
85
|
+
# # Schedule strings that can be evals to a job object
|
86
|
+
# Threasy.schedule("BackgroundJob.new", every: 1.day)
|
87
|
+
#
|
88
|
+
# === Parameters
|
89
|
+
#
|
90
|
+
# * `job` - Job object which responds to `perform` or `call`
|
91
|
+
# * `options`
|
92
|
+
# * `every: n` - If present, job is repeated every `n` seconds
|
93
|
+
# * `in: n` - `n` seconds until job is executed
|
94
|
+
# * `at: Time` - Time to execute job at
|
95
|
+
# * `&block` - Job block
|
96
|
+
#
|
97
|
+
# Must have either a `job` object or job `&block` present.
|
98
|
+
#
|
99
|
+
# === Returns
|
100
|
+
#
|
101
|
+
# * `Threasy::Schedule::Entry` if job was successfully added to schedule
|
102
|
+
# * `nil` if job was for the past
|
32
103
|
def self.schedule(*args, &block)
|
33
104
|
schedules.add *args, &block
|
34
105
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -26,6 +26,16 @@ describe "Threasy::Schedule" do
|
|
26
26
|
end
|
27
27
|
end
|
28
28
|
end
|
29
|
+
|
30
|
+
it "should add jobs scheduled for the future" do
|
31
|
+
expect(subject).to receive(:add_entry)
|
32
|
+
subject.add(job, at: Time.now + 100)
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should ignore jobs scheduled for the past" do
|
36
|
+
expect(subject).not_to receive(:add_entry)
|
37
|
+
subject.add(job, at: Time.now - 100)
|
38
|
+
end
|
29
39
|
end
|
30
40
|
|
31
41
|
describe "#remove" do
|
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.3.
|
4
|
+
version: 0.3.2
|
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-
|
11
|
+
date: 2015-08-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|