timemachine 1.0.2 → 1.0.3

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
  SHA256:
3
- metadata.gz: 8e7ac7abf883d644a39c82488c2b68d3101ca88be93def55b73936bb63763088
4
- data.tar.gz: 109ad5b6a6332a35749b30b49f73c0275afdbcae6e8e57e7da97baf612f6cafa
3
+ metadata.gz: 412ae253c1cf57715d748a498fe09daf146813c9ec7e9592ca6eccfd6e905b8c
4
+ data.tar.gz: 767286f421b3706e1ae7e9ad7c69c5c26ddf2808494e03f67bf7d1beba29523c
5
5
  SHA512:
6
- metadata.gz: d7da01766f279c03906c5727d8891c02cb50bf38707e37d277fc3d6929453fc0f51f1504c0954ac513ebc9d91ee1fc80b710e0918ef02450a35e319239ba99ac
7
- data.tar.gz: c29e266dfdc9b98736b76ff784921a8abc6000b733f0aca397ba2cfbc5e8066e71766d6dd020c77129a7df9e6692b6744e8d7b9d4b8b3f2bd5822ad72a13e583
6
+ metadata.gz: 521d3ec7fd877e8b42532fc371044b7bc6d5bcf45ffd5905be5a708d00579973be49e57937af99a2e85208b8d448839bea76b07a12475713c33d480184b472fc
7
+ data.tar.gz: dc7e27cc48e54c8d4a3ded22d3e4a5e11da96183389f2864bdb71e028340555d9deb52c9bd4aa2461c2e81c1ef5c790c382977a23859f6a5c139e2995e77bdaf
data/lib/executor.rb CHANGED
@@ -1,7 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TimeMachine
4
+ #
5
+ # Executors contains executor interface and implementations.
6
+ # An executor is where a timed-up task is actually executed,
7
+ # thus decoupled with the scheduler.
8
+ #
4
9
  module Executors
10
+ #
11
+ # The base class (interface) for a executor.
12
+ #
5
13
  class Executor
6
14
  def execute(&block)
7
15
  raise NotImplementedError
@@ -4,6 +4,11 @@ require 'executor'
4
4
 
5
5
  module TimeMachine
6
6
  module Executors
7
+ #
8
+ # ThreadExecutor is currently the only implementation of Executor.
9
+ # It executes the task in a background thread, so slow tasks will not
10
+ # block the scheduler.
11
+ #
7
12
  class ThreadExecutor < Executor
8
13
  def execute(&block)
9
14
  Thread.new(&block)
data/lib/timemachine.rb CHANGED
@@ -2,18 +2,48 @@
2
2
 
3
3
  require 'thread_executor'
4
4
 
5
+ #
6
+ # Namespace TimeMachine contains all the magics of this gem.
7
+ #
5
8
  module TimeMachine
9
+
10
+ #
11
+ # The internal struct to store a task.
12
+ #
6
13
  TimedTask = Struct.new(:handle, :timeup, :block)
14
+
15
+ #
16
+ # The struct to store the result of a task.
17
+ #
7
18
  TaskResult = Struct.new(:handle, :status, :record_result, :result)
8
19
 
20
+ #
21
+ # `DuplicateHandleError` is thrown when the handle (name) for a new task collides with a existing one.
22
+ #
9
23
  class DuplicateHandleError < RuntimeError; end
10
24
 
25
+ #
26
+ # The core of this gem, which is responsible for scheduling tasks.
27
+ #
11
28
  class TimeMachine
29
+ # Default timeout of the scheduler, used when the scheduler is idle.
12
30
  SCHEDULER_DEFAULT_TIMEOUT = 3
31
+
32
+ # Length of the handle generated by `TimeMachine`.
13
33
  RANDOM_HANDLE_LENGTH = 16
34
+
14
35
  private_constant :SCHEDULER_DEFAULT_TIMEOUT
15
36
 
16
37
  public
38
+ #
39
+ # Create a new `TimeMachine`.
40
+ #
41
+ # @param [Executors::Executor] executor The task executor to be used. Defaults to a `Executors::ThreadExecutor`.
42
+ # @param [Boolean] more_timely Use a lock in scheduler. This avoids a border case that a task is submitted while
43
+ # the scheduler is scheduling, thus not asleep. If `more_timely` is set to `false` in such case, the task
44
+ # submission will not effectively preempt the scheduler, and will have to wait one more round before it is scheduled,
45
+ # and therefore may cause a slight delay.
46
+ #
17
47
  def initialize(executor= Executors::ThreadExecutor.new, more_timely=false)
18
48
  @running = false
19
49
  @timeout_queue = []
@@ -28,6 +58,18 @@ module TimeMachine
28
58
  @user_mut = Mutex.new
29
59
  end
30
60
 
61
+ #
62
+ # Execute the given block at the given timeup.
63
+ #
64
+ # @param [Time] timeup The time to invoke the given block
65
+ # @param [String] name A custom name (handle) for the task. If `nil`, one will be generated. If specified,
66
+ # should not be duplicate with an existing one.
67
+ # @param [Boolean] record_result Whether to save the result after completion.
68
+ # @param [Proc] &block The block to execute.
69
+ #
70
+ # @return [String] A handle to the task, either the name passed in (if given) or generated by `TimeMachine`.
71
+ # Can be used to cancel the task or query task status and result (if `record_result` is set).
72
+ #
31
73
  def at(timeup, name: nil, record_result: false, &block)
32
74
  handle = name || _generate_handle
33
75
 
@@ -44,16 +86,46 @@ module TimeMachine
44
86
  handle
45
87
  end
46
88
 
89
+ #
90
+ # Execute the given block after given timeout.
91
+ #
92
+ # @param [Float] timeout Timeout in seconds.
93
+ # @param [String] name A custom name (handle) for the task. If `nil`, one will be generated. If specified,
94
+ # should not be duplicate with an existing one.
95
+ # @param [Boolean] record_result Whether to save the result after completion.
96
+ # @param [Proc] &block The block to execute.
97
+ #
98
+ # @return [String] A handle to the task, either the name passed in (if given) or generated by `TimeMachine`.
99
+ # Can be used to cancel the task or query task status and result (if `record_result` is set).
100
+ #
47
101
  def after(timeout, name: nil, record_result: false, &block)
48
102
  at(Time.now + timeout, name: name, record_result: record_result, &block)
49
103
  end
50
104
 
105
+ #
106
+ # Get the result of a given block.
107
+ #
108
+ #
109
+ # @param [String] handle The handle to the task, typically returned by previous `at` and `after` calls.
110
+ #
111
+ # @return [TaskResult] The result of the given task. If not found, or the task is finished with `record_result`
112
+ # unset, returns `nil`.
113
+ #
51
114
  def get_result(handle)
52
115
  @user_mut.synchronize do
53
116
  @result_queue[handle]
54
117
  end
55
118
  end
56
119
 
120
+ #
121
+ # Get the result of a given block, and delete it from `TimeMachine`'s internal storage if it is finished or cancelled.
122
+ # *Remember to call this, or the results will pile up and eat your memory!*
123
+ #
124
+ # @param [String] handle The handle to the task, typically returned by previous `at` and `after` calls.
125
+ #
126
+ # @return [TaskResult] The result of the given task. If not found, or the task is finished with `record_result`
127
+ # unset, returns `nil`. If the task is finished or cancelled, it will be deleted from `TimeMachine` storage as well.
128
+ #
57
129
  def pop_result(handle)
58
130
  @user_mut.synchronize do
59
131
  res = @result_queue[handle]
@@ -65,6 +137,13 @@ module TimeMachine
65
137
  end
66
138
  end
67
139
 
140
+ #
141
+ # Cancel a previously submitted task.
142
+ # Be sure to cancel it in time if you mean to cancel it.
143
+ # *If the task has already been scheduled or executed, cancel may not take effect.*
144
+ #
145
+ # @param [String] handle The handle to the task, typically returned by previous `at` and `after` calls.
146
+ #
68
147
  def cancel(handle)
69
148
  @user_mut.synchronize do
70
149
  @cancel_queue << handle
@@ -72,6 +151,9 @@ module TimeMachine
72
151
  _bg_wakeup
73
152
  end
74
153
 
154
+ #
155
+ # Start the `TimeMachine`. This will create a background scheduler thread.
156
+ #
75
157
  def start()
76
158
  @user_mut.synchronize do
77
159
  return if @running
@@ -80,6 +162,9 @@ module TimeMachine
80
162
  end
81
163
  end
82
164
 
165
+ #
166
+ # Stop the `TimeMachine`. All tasks due after this call will be cancelled.
167
+ #
83
168
  def stop()
84
169
  @user_mut.synchronize do
85
170
  return unless @running
@@ -100,7 +185,7 @@ module TimeMachine
100
185
 
101
186
  def _bg_wakeup
102
187
  @scheduler_mut&.lock
103
- @scheduler_thread.run
188
+ @scheduler_thread&.run
104
189
  @scheduler_mut&.unlock
105
190
  end
106
191
 
@@ -135,10 +220,11 @@ module TimeMachine
135
220
  @scheduler_mut&.lock
136
221
  end
137
222
  @scheduler_mut&.unlock
223
+ @scheduler_thread = nil
138
224
  end
139
225
 
140
226
  def _bg_enqueueTask(task)
141
- return if @result_queue[task.handle].status != :UNSCHEDULED
227
+ return if @result_queue[task.handle]&.status != :UNSCHEDULED
142
228
 
143
229
  @result_queue[task.handle].status = :PENDING
144
230
  @timeout_queue.insert(@timeout_queue.index do |t|
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: timemachine
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.2
4
+ version: 1.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - LTW