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