threasy 0.3.0 → 0.3.2
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 +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
|