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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 864b05c24ba407f0763f65f7a07e1af3d9678efd
4
- data.tar.gz: c83f33b9c2ea06fa1783ba51b51b07948920e359
3
+ metadata.gz: 24769445131b62b227817a4cd7eacf4682e3855e
4
+ data.tar.gz: f5d317aee9b0de3f7b4989526b8716738f9f45fb
5
5
  SHA512:
6
- metadata.gz: cb206f8de354b6192c0bb5153cedda328b9d928abedf86423bcdc1e601c720bdb312c87b9bde65353d73a03f8f1a0ccc7384ffe80c60e837c7be53c443751a48
7
- data.tar.gz: ca0f60b71576b34b325cf7bc2a3c94a793f1c52ede65fe9ef79914414417303c59a54d5a7c04828c333fdda89c5be4d17e37a4b85f0cdaa17b4c3d576fd5ad72
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 = {})
@@ -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
- add_entry Entry.new(job, {schedule: self}.merge(options))
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
@@ -1,3 +1,3 @@
1
1
  module Threasy
2
- VERSION = "0.3.0"
2
+ VERSION = "0.3.2"
3
3
  end
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
- # sync do
42
- log "Adding new worker to pool"
43
- worker = Worker.new(self, size)
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
@@ -1,7 +1,6 @@
1
- # require 'pry'
1
+ $LOAD_PATH.unshift File.join(File.dirname(__FILE__), "..", "lib")
2
2
  require 'timecop'
3
-
4
- require File.join(File.dirname(__FILE__), "..", "lib", "threasy")
3
+ require 'threasy'
5
4
 
6
5
  def async(timeout = 10)
7
6
  t = Thread.new do
@@ -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.0
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-17 00:00:00.000000000 Z
11
+ date: 2015-08-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler