standard_procedure_operations 0.7.1 → 0.7.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 +4 -4
- data/README.md +17 -5
- data/app/jobs/operations/wake_task_job.rb +1 -1
- data/app/models/operations/task/plan.rb +10 -0
- data/app/models/operations/task.rb +39 -16
- data/lib/operations/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 24336966a7874886f00207073fbe8f5f3f53d55bb7594c8c36d085f4c74dd369
|
4
|
+
data.tar.gz: 3bdf232858859b1003c7b90c911932aa5e4e7c321a0fefbcbcfc62c49801cda2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1398774410e430157a8cd45e874ca1cd631ccc3159d554d32b573d4e6f261504727b31aceaf05340c4a75f60d87309977485f163bcf79b1dc15fb7fa0a1d20d2
|
7
|
+
data.tar.gz: 7ee18d5f9889f902f74bc5277f71e72d1d029676bb39fe2dae7d3185accded3d3573f2b784233b21c4830b6422771ea9d47e3281975230c97eddd931c61623d2
|
data/README.md
CHANGED
@@ -9,7 +9,7 @@ In effect, that flowchart is a state machine - with "decision states" and "actio
|
|
9
9
|
|
10
10
|
## Breaking Change
|
11
11
|
|
12
|
-
Version 0.7.0 includes breaking changes.
|
12
|
+
Version 0.7.0 includes breaking changes. When you run `bin/rails operations:migrations:install` one of the migrations will drop your existing `operations_tasks` and `operations_task_participants` tables. If you need the historic data in those tables, then edit the migration to rename the tables instead. Also you will need to update your tests to use the new `test` method.
|
13
13
|
|
14
14
|
## Usage
|
15
15
|
|
@@ -193,7 +193,7 @@ end
|
|
193
193
|
```
|
194
194
|
#### Wait handlers
|
195
195
|
|
196
|
-
The registration process performs an action, `send_invitation` and then waits until a `name_provided?`. A `wait handler` is similar to a `decision handler` but if the conditions are not met, instead of raising an error, the task goes to sleep. A background process (see
|
196
|
+
The registration process performs an action, `send_invitation` and then waits until a `name_provided?`. A `wait handler` is similar to a `decision handler` but if the conditions are not met, instead of raising an error, the task goes to sleep. A background process (see below) wakes the task periodically to reevaluate the condition. Or, an `interaction` can be triggered; this is similar to an action because it does something, but it also immediately reevaluates the current wait handler. So in this case, when the `register!` interaction completes, the `name_provided?` wait handler is reevaluated and, because the `name` has now been supplied, it can move on to the `create_user` state.
|
197
197
|
|
198
198
|
When a task reaches a wait handler, it goes to sleep and expects to be woken up at some point in the future. You can specify how often it is woken up by adding a `delay 10.minutes` declaration to your class. The default is `1.minute`. Likewise, if a task does not change state after a certain period it fails with an `Operations::Timeout` exception. You can set this timeout by declaring `timeout 48.hours` (the default is `24.hours`).
|
199
199
|
|
@@ -217,6 +217,18 @@ If you want the task to be run completely in the background (so it sleeps immedi
|
|
217
217
|
|
218
218
|
[Example wait and interaction handlers](spec/examples/waiting_and_interactions_spec.rb)
|
219
219
|
|
220
|
+
Because background tasks are woken using ActiveJob, you may wish to control exactly how these jobs are handled.
|
221
|
+
|
222
|
+
You can specify which ActiveJob queue they are placed on (with the default value being `:default`) - this is the equivalent of setting `queue_as :my_queue` in ActiveJob. And you can even specify which queue adapter they use (if, for example, you want to use SolidQueue for most of your background jobs, but Sidekiq for a certain subset of tasks).
|
223
|
+
|
224
|
+
```ruby
|
225
|
+
class MyBackgroundOperation < Operations::Task
|
226
|
+
queue :low_priority
|
227
|
+
runs_on :sidekiq
|
228
|
+
# ...
|
229
|
+
end
|
230
|
+
```
|
231
|
+
|
220
232
|
### Sub tasks
|
221
233
|
|
222
234
|
If your task needs to start sub-tasks, it can use the `start` method, passing the sub-task class and arguments.
|
@@ -298,10 +310,10 @@ class WeekendChecker < Operations::Task
|
|
298
310
|
result :weekday
|
299
311
|
end
|
300
312
|
|
301
|
-
task = WeekendChecker.
|
313
|
+
task = WeekendChecker.test :is_it_the_weekend?, day_of_week: "Saturday"
|
302
314
|
expect(task).to be_in :weekend
|
303
315
|
|
304
|
-
task = WeekendChecker.
|
316
|
+
task = WeekendChecker.test :is_it_the_weekend?, day_of_week: "Wednesday"
|
305
317
|
expect(task).to be_in :weekday
|
306
318
|
```
|
307
319
|
|
@@ -350,4 +362,4 @@ The gem is available as open source under the terms of the [LGPL License](/LICEN
|
|
350
362
|
- [x] Add visualization export for task flows
|
351
363
|
- [ ] Replace ActiveJob with a background process
|
352
364
|
- [ ] Rename StateManagent with Plan
|
353
|
-
- [ ] Add interactions
|
365
|
+
- [ ] Add interactions
|
@@ -32,6 +32,12 @@ module Operations::Task::Plan
|
|
32
32
|
|
33
33
|
def timeout(value) = @execution_timeout = value
|
34
34
|
|
35
|
+
def queue(value) = @queue_as = value
|
36
|
+
|
37
|
+
def runs_on(value) = @queue_adapter ||= value
|
38
|
+
alias_method :runs, :runs_on
|
39
|
+
alias_method :runs_using, :runs_on
|
40
|
+
|
35
41
|
def delete_after(value) = @deletion_time = value
|
36
42
|
|
37
43
|
def on_timeout(&handler) = @on_timeout = handler
|
@@ -40,6 +46,10 @@ module Operations::Task::Plan
|
|
40
46
|
|
41
47
|
def execution_timeout = @execution_timeout ||= 24.hours
|
42
48
|
|
49
|
+
def queue_as = @queue_as ||= :default
|
50
|
+
|
51
|
+
def queue_adapter = @queue_adapter ||= Operations::WakeTaskJob.queue_adapter
|
52
|
+
|
43
53
|
def timeout_handler = @on_timeout
|
44
54
|
|
45
55
|
def deletion_time = @deletion_time ||= 90.days
|
@@ -5,17 +5,18 @@ module Operations
|
|
5
5
|
include Index
|
6
6
|
include Testing
|
7
7
|
|
8
|
+
scope :active, -> { where(status: %w[active waiting]) }
|
8
9
|
scope :ready_to_wake, -> { ready_to_wake_at(Time.current) }
|
9
|
-
scope :ready_to_wake_at, ->(time) { where(wakes_at: ..time) }
|
10
|
+
scope :ready_to_wake_at, ->(time) { waiting.where(wakes_at: ..time) }
|
10
11
|
scope :expired, -> { expires_at(Time.current) }
|
11
|
-
scope :expired_at, ->(time) { where(expires_at: ..time) }
|
12
|
+
scope :expired_at, ->(time) { waiting.where(expires_at: ..time) }
|
12
13
|
scope :ready_to_delete, -> { ready_to_delete_at(Time.current) }
|
13
14
|
scope :ready_to_delete_at, ->(time) { where(delete_at: ..time) }
|
14
15
|
|
15
16
|
# Task hierarchy relationships
|
16
17
|
belongs_to :parent, class_name: "Operations::Task", optional: true
|
17
18
|
has_many :sub_tasks, class_name: "Operations::Task", foreign_key: "parent_id", dependent: :nullify
|
18
|
-
has_many :active_sub_tasks, -> {
|
19
|
+
has_many :active_sub_tasks, -> { active }, class_name: "Operations::Task", foreign_key: "parent_id"
|
19
20
|
has_many :failed_sub_tasks, -> { failed }, class_name: "Operations::Task", foreign_key: "parent_id"
|
20
21
|
has_many :completed_sub_tasks, -> { completed }, class_name: "Operations::Task", foreign_key: "parent_id"
|
21
22
|
|
@@ -26,16 +27,18 @@ module Operations
|
|
26
27
|
has_attribute :exception_backtrace, :string
|
27
28
|
|
28
29
|
def call(immediate: false)
|
29
|
-
|
30
|
+
state = ""
|
31
|
+
while active? && (state != current_state)
|
32
|
+
state = current_state
|
30
33
|
Rails.logger.debug { "--- #{self}: #{current_state}" }
|
31
|
-
(
|
34
|
+
(immediate || state_is_immediate?(current_state)) ? call_handler : go_to_sleep!
|
32
35
|
end
|
33
36
|
rescue => ex
|
34
37
|
record_error! ex
|
35
38
|
raise ex
|
36
39
|
end
|
37
40
|
|
38
|
-
def go_to(next_state) = update! current_state: next_state
|
41
|
+
def go_to(next_state) = update! current_state: next_state, task_status: (state_is_immediate?(next_state) ? "active" : "waiting")
|
39
42
|
|
40
43
|
def wake_up! = timeout_expired? ? call_timeout_handler : activate_and_call
|
41
44
|
|
@@ -45,6 +48,8 @@ module Operations
|
|
45
48
|
|
46
49
|
def call_handler = handler_for(current_state).call(self)
|
47
50
|
|
51
|
+
private def state_is_immediate?(state) = handler_for(state).immediate?
|
52
|
+
|
48
53
|
private def go_to_sleep! = update!(default_times.merge(task_status: "waiting"))
|
49
54
|
|
50
55
|
private def activate_and_call
|
@@ -59,16 +64,34 @@ module Operations
|
|
59
64
|
raise ex
|
60
65
|
end
|
61
66
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
67
|
+
class << self
|
68
|
+
def call(task_status: "active", **attributes)
|
69
|
+
create!(attributes.merge(task_status: task_status, current_state: initial_state).merge(default_times)).tap do |t|
|
70
|
+
t.call
|
71
|
+
end
|
72
|
+
end
|
73
|
+
alias_method :perform_now, :call
|
74
|
+
|
75
|
+
def later(**attributes) = call(task_status: "waiting", **attributes)
|
76
|
+
alias_method :perform_later, :later
|
77
|
+
|
78
|
+
def wake_sleeping
|
79
|
+
adapter = Operations::WakeTaskJob.queue_adapter
|
80
|
+
begin
|
81
|
+
Task.ready_to_wake.find_each do |task|
|
82
|
+
Operations::WakeTaskJob.queue_adapter = task.class.queue_adapter
|
83
|
+
Operations::WakeTaskJob.perform_later task
|
84
|
+
end
|
85
|
+
ensure
|
86
|
+
Operatives::WakeTaskJob.queue_adapter = adapter
|
87
|
+
end
|
88
|
+
end
|
71
89
|
|
72
|
-
|
90
|
+
def delete_old
|
91
|
+
Task.ready_to_delete.find_each do |t|
|
92
|
+
Operations::DeleteOldTaskJob.perform_later(t)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
73
96
|
end
|
74
97
|
end
|
data/lib/operations/version.rb
CHANGED
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: standard_procedure_operations
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.7.
|
4
|
+
version: 0.7.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rahoul Baruah
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date:
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: rails
|
@@ -98,7 +98,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
98
98
|
- !ruby/object:Gem::Version
|
99
99
|
version: '0'
|
100
100
|
requirements: []
|
101
|
-
rubygems_version: 3.6.
|
101
|
+
rubygems_version: 3.6.7
|
102
102
|
specification_version: 4
|
103
103
|
summary: Operations
|
104
104
|
test_files: []
|