pgbus 0.20.1 → 0.21.1
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/CHANGELOG.md +66 -8
- data/README.md +1 -1
- data/app/helpers/pgbus/workflow_insights_helper.rb +8 -0
- data/app/models/pgbus/workflow_entry.rb +3 -2
- data/app/views/pgbus/workflows/definitions/_step_card.html.erb +3 -0
- data/config/locales/da.yml +3 -0
- data/config/locales/de.yml +3 -0
- data/config/locales/en.yml +3 -0
- data/config/locales/es.yml +3 -0
- data/config/locales/fi.yml +3 -0
- data/config/locales/fr.yml +3 -0
- data/config/locales/it.yml +3 -0
- data/config/locales/ja.yml +3 -0
- data/config/locales/nb.yml +3 -0
- data/config/locales/nl.yml +3 -0
- data/config/locales/pt.yml +3 -0
- data/config/locales/sv.yml +3 -0
- data/lib/generators/pgbus/templates/add_workflows.rb.erb +3 -1
- data/lib/generators/pgbus/templates/migration.rb.erb +3 -1
- data/lib/pgbus/batch/sweep.rb +10 -5
- data/lib/pgbus/client.rb +109 -42
- data/lib/pgbus/configuration/workflow_settings.rb +1 -1
- data/lib/pgbus/mcp/tools/workflow_stats_tool.rb +1 -1
- data/lib/pgbus/mcp/tools/workflows_attention_tool.rb +1 -1
- data/lib/pgbus/version.rb +1 -1
- data/lib/pgbus/web/data_source/workflow_list.rb +6 -4
- data/lib/pgbus/web/data_source.rb +39 -22
- data/lib/pgbus/web/workflow_insights_report.rb +11 -3
- data/lib/pgbus/web/workflow_state.rb +5 -2
- data/lib/pgbus/workflow/instance.rb +36 -3
- data/lib/pgbus/workflow/runner.rb +2 -2
- data/lib/pgbus/workflow/signal_peek.rb +47 -0
- data/lib/pgbus/workflow/signals.rb +31 -10
- data/lib/pgbus/workflow/step_definition.rb +45 -3
- data/lib/pgbus/workflow/step_execution.rb +27 -10
- data/lib/pgbus/workflow/wait_timeout.rb +38 -7
- data/lib/pgbus/workflow.rb +11 -5
- data/sig/pgbus/client.rbs +7 -5
- data/sig/pgbus.rbs +43 -0
- metadata +2 -1
|
@@ -15,8 +15,11 @@ module Pgbus
|
|
|
15
15
|
# (job_options:) may set. Anything else raises at class load.
|
|
16
16
|
JOB_OPTIONS = %i[queue priority wait wait_until].freeze
|
|
17
17
|
|
|
18
|
+
# wait_timeout is the static wait_timeout: in seconds (nil for a per-run
|
|
19
|
+
# one); wait_timeout_callable the per-run one as given, a lambda or a
|
|
20
|
+
# method name (issue #574).
|
|
18
21
|
attr_reader :name, :body, :wait, :skip_if, :job_options, :timeout, :exception_policies,
|
|
19
|
-
:wait_for, :wait_for_name, :wait_timeout, :on_timeout
|
|
22
|
+
:wait_for, :wait_for_name, :wait_timeout, :wait_timeout_callable, :on_timeout
|
|
20
23
|
|
|
21
24
|
def self.validate_job_options!(options)
|
|
22
25
|
raise ArgumentError, "job_options: must be a Hash, got #{options.inspect}" unless options.is_a?(Hash)
|
|
@@ -104,6 +107,44 @@ module Pgbus
|
|
|
104
107
|
result ? true : false
|
|
105
108
|
end
|
|
106
109
|
|
|
110
|
+
# True when wait_timeout: is a lambda or a method name, evaluated per run.
|
|
111
|
+
def dynamic_wait_timeout? = !wait_timeout_callable.nil?
|
|
112
|
+
|
|
113
|
+
# The timeout_at of the step parking now on +workflow+: now plus a
|
|
114
|
+
# static wait_timeout:, what a per-run one returns (a deadline already
|
|
115
|
+
# past is now, so the next sweep applies on_timeout), or nil.
|
|
116
|
+
def timeout_at_for(workflow, now)
|
|
117
|
+
return now + wait_timeout if wait_timeout
|
|
118
|
+
return nil unless dynamic_wait_timeout?
|
|
119
|
+
|
|
120
|
+
deadline = resolve_wait_timeout(workflow)
|
|
121
|
+
deadline.is_a?(Time) ? [deadline, now].max : deadline && (now + deadline)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# What the per-run wait_timeout: returns on +workflow+: a Time (an
|
|
125
|
+
# absolute deadline), seconds from now, or nil (no timeout). It runs as
|
|
126
|
+
# a guard does (a flow-control verb raises NotInStep), in a savepoint:
|
|
127
|
+
# a query of its own that fails in the database must not abort the
|
|
128
|
+
# run's transaction, which the step's outcome is written in. Anything
|
|
129
|
+
# else raises ArgumentError, as an error it raises goes up, for the
|
|
130
|
+
# step's exception policies.
|
|
131
|
+
def resolve_wait_timeout(workflow)
|
|
132
|
+
callable = wait_timeout_callable
|
|
133
|
+
value = WorkflowEntry.transaction(requires_new: true) do
|
|
134
|
+
workflow.send(:guarding) { callable.is_a?(Symbol) ? workflow.send(callable) : workflow.instance_exec(&callable) }
|
|
135
|
+
end
|
|
136
|
+
return nil if value.nil?
|
|
137
|
+
if value.is_a?(Numeric) || self.class.duration?(value)
|
|
138
|
+
return self.class.seconds(value, "wait_timeout (step #{name})", positive: true)
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
time = value.to_time if value.respond_to?(:to_time) && !value.is_a?(String)
|
|
142
|
+
return time if time.is_a?(Time)
|
|
143
|
+
|
|
144
|
+
raise ArgumentError, "wait_timeout: of step #{name} must return a Time, a Duration, a number of seconds or nil, " \
|
|
145
|
+
"got #{value.inspect}"
|
|
146
|
+
end
|
|
147
|
+
|
|
107
148
|
private
|
|
108
149
|
|
|
109
150
|
def assign_wait(wait_for, wait_timeout, on_timeout)
|
|
@@ -112,8 +153,9 @@ module Pgbus
|
|
|
112
153
|
raise ArgumentError, "on_timeout: needs wait_for: and wait_timeout:" if !on_timeout.nil? && (@wait_for.nil? || wait_timeout.nil?)
|
|
113
154
|
raise ArgumentError, "wait_timeout: needs wait_for: (it bounds the wait for a signal)" if wait_timeout && @wait_for.nil?
|
|
114
155
|
|
|
115
|
-
@
|
|
116
|
-
@
|
|
156
|
+
@wait_timeout_callable = wait_timeout if wait_timeout.is_a?(Symbol) || wait_timeout.is_a?(Proc)
|
|
157
|
+
@wait_timeout = @wait_timeout_callable ? nil : self.class.seconds(wait_timeout, "wait_timeout", positive: true)
|
|
158
|
+
@on_timeout = (@wait_timeout || @wait_timeout_callable) && normalize_on_timeout(on_timeout.nil? ? :pause! : on_timeout)
|
|
117
159
|
end
|
|
118
160
|
|
|
119
161
|
def normalize_on_timeout(value)
|
|
@@ -13,7 +13,8 @@ module Pgbus
|
|
|
13
13
|
# heartbeat is on: its worker died, and the stall action applies now.
|
|
14
14
|
# 2. Guards, still under the lock: the class or the step no longer
|
|
15
15
|
# defined (pause with StepNotDefined, or skip a removed_step),
|
|
16
|
-
# cancel_if, skip_if
|
|
16
|
+
# cancel_if, skip_if (which read woken? and signal_ready? through the
|
|
17
|
+
# attempt's SignalPeek), then a wait_for: step's signal gate.
|
|
17
18
|
# 3. The body, outside any transaction, inside `catch` for the
|
|
18
19
|
# flow-control verbs and `rescue StandardError` for the policies.
|
|
19
20
|
# 4. The outcome, under the lock again (StepOutcome).
|
|
@@ -21,7 +22,9 @@ module Pgbus
|
|
|
21
22
|
# Whatever the step's outcome, the job itself completes normally: the
|
|
22
23
|
# step row and the pgbus.workflow.* events carry the truth.
|
|
23
24
|
class StepExecution
|
|
24
|
-
|
|
25
|
+
# +adopt_held+: a guard raised before the gate, so the signal the step
|
|
26
|
+
# holds is put on this attempt's row before its outcome (Signals.adopt_held).
|
|
27
|
+
Claim = Data.define(:record, :step, :klass, :definition, :workflow, :guard_error, :adopt_held)
|
|
25
28
|
|
|
26
29
|
def initialize(step_id, delivery: Pgbus::ActiveJob::Delivery.current, config: Pgbus.configuration)
|
|
27
30
|
@step_id = step_id
|
|
@@ -103,15 +106,23 @@ module Pgbus
|
|
|
103
106
|
return undefined!(record, step, notes, "#{record.workflow_class} is not a Pgbus::Workflow class any more") unless klass
|
|
104
107
|
|
|
105
108
|
unless definition
|
|
106
|
-
|
|
109
|
+
if klass.workflow_steps.removed?(step.step_name)
|
|
110
|
+
# The definition is gone, so whether it waited is unknown: look for a
|
|
111
|
+
# held signal only where the signal schema exists.
|
|
112
|
+
Signals.adopt_held(step, WorkflowSignal.held_by_step(record.workflow_id, step.step_name)) if Sweep.waiting_ready?
|
|
113
|
+
return skip!(record, step, notes, klass)
|
|
114
|
+
end
|
|
107
115
|
|
|
108
116
|
return undefined!(record, step, notes, "#{klass.name} has no step #{step.step_name} " \
|
|
109
117
|
"(declare `removed_step :#{step.step_name}` to skip it)")
|
|
110
118
|
end
|
|
111
119
|
|
|
112
120
|
workflow = klass.new(record)
|
|
113
|
-
|
|
114
|
-
|
|
121
|
+
peek = SignalPeek.new(record, step, definition)
|
|
122
|
+
workflow.send(:enter_step, StepContext::Attempt.new(step_id: step.id, step_name: step.step_name, attempt: step.attempt),
|
|
123
|
+
signals: peek)
|
|
124
|
+
claim = Claim.new(record: record, step: step, klass: klass, definition: definition, workflow: workflow, guard_error: nil,
|
|
125
|
+
adopt_held: false)
|
|
115
126
|
begin
|
|
116
127
|
verdict = workflow.send(:guarding) do
|
|
117
128
|
next FlowControl::Outcome.cancel if cancel?(klass, workflow)
|
|
@@ -119,20 +130,23 @@ module Pgbus
|
|
|
119
130
|
FlowControl::Outcome.skip if definition.skip?(workflow)
|
|
120
131
|
end
|
|
121
132
|
rescue StandardError => e
|
|
122
|
-
return claim.with(guard_error: e)
|
|
133
|
+
return claim.with(guard_error: e, adopt_held: definition.waits_for_signal?)
|
|
134
|
+
end
|
|
135
|
+
if verdict
|
|
136
|
+
Signals.adopt_held(step, peek.held)
|
|
137
|
+
return outcome!(record, step, notes, klass, verdict)
|
|
123
138
|
end
|
|
124
|
-
return outcome!(record, step, notes, klass, verdict) if verdict
|
|
125
139
|
|
|
126
|
-
gate(record, step, definition, workflow, claim)
|
|
140
|
+
gate(record, step, definition, workflow, claim, peek)
|
|
127
141
|
end
|
|
128
142
|
|
|
129
143
|
# A wait_for: step runs only with a signal (or once its wait timed
|
|
130
144
|
# out); without one it parks and this delivery ends. A matcher that
|
|
131
145
|
# raises is handed to the exception policies, like a guard.
|
|
132
|
-
def gate(record, step, definition, workflow, claim)
|
|
146
|
+
def gate(record, step, definition, workflow, claim, peek)
|
|
133
147
|
return claim unless definition.waits_for_signal?
|
|
134
148
|
|
|
135
|
-
Signals.gate(record, step, definition, workflow) ? claim : nil
|
|
149
|
+
Signals.gate(record, step, definition, workflow, peek: peek) ? claim : nil
|
|
136
150
|
rescue StandardError => e
|
|
137
151
|
claim.with(guard_error: e)
|
|
138
152
|
end
|
|
@@ -185,6 +199,9 @@ module Pgbus
|
|
|
185
199
|
next park_fan_out(record, claim, outcome, notes) if outcome&.action == :fan_out
|
|
186
200
|
|
|
187
201
|
notes.report(decision.handler_error, handler_context(claim)) if decision&.handler_error
|
|
202
|
+
# Here rather than in the claim's transaction, which the statement
|
|
203
|
+
# a guard failed on may have aborted.
|
|
204
|
+
Signals.adopt_held(claim.step, SignalPeek.new(record, claim.step, claim.definition).held) if claim.adopt_held
|
|
188
205
|
StepOutcome.apply(record, claim.step, outcome, notes: notes, error: error, output: claim.workflow.pending_output,
|
|
189
206
|
report: decision ? decision.report : true, duration: duration,
|
|
190
207
|
klass: claim.klass)
|
|
@@ -14,7 +14,8 @@ module Pgbus
|
|
|
14
14
|
# received_signal nil and timed_out? true
|
|
15
15
|
# :notify only the event and the instrumentation (issue #565): the
|
|
16
16
|
# same attempt keeps waiting and timeout_at moves to its next
|
|
17
|
-
# deadline, one wait_timeout on (see next_deadline)
|
|
17
|
+
# deadline, one wait_timeout on (see next_deadline); a per-run
|
|
18
|
+
# wait_timeout: is evaluated again for it (see notify_deadline)
|
|
18
19
|
#
|
|
19
20
|
# A signal that arrives after the timeout fired stays pending, like any
|
|
20
21
|
# signal no step waits for, except under :notify, whose step still waits
|
|
@@ -56,12 +57,12 @@ module Pgbus
|
|
|
56
57
|
timeout_at: step.timeout_at&.utc&.iso8601(3) }.compact)
|
|
57
58
|
notes.instrument("pgbus.workflow.wait_timed_out",
|
|
58
59
|
Runner.payload_for(record, step_name: step.step_name, attempt: step.attempt, action: action.to_s))
|
|
59
|
-
apply(record, step, action, notes: notes, now: now,
|
|
60
|
+
apply(record, step, action, notes: notes, now: now, definition: definition)
|
|
60
61
|
action
|
|
61
62
|
end
|
|
62
63
|
|
|
63
|
-
def apply(record, step, action, notes:, now:,
|
|
64
|
-
return notify!(step,
|
|
64
|
+
def apply(record, step, action, notes:, now:, definition: nil)
|
|
65
|
+
return notify!(record, step, definition, notes: notes, now: now) if action == :notify
|
|
65
66
|
return Waiting.wake!(record, step, now: now, timeout_at: [step.timeout_at, now].compact.min) if action == :run
|
|
66
67
|
|
|
67
68
|
error = action == :pause! ? timed_out_error(step, now) : nil
|
|
@@ -69,12 +70,42 @@ module Pgbus
|
|
|
69
70
|
end
|
|
70
71
|
|
|
71
72
|
# The run and the step row stay as they are (no outcome, no StepJob);
|
|
72
|
-
# only timeout_at moves.
|
|
73
|
-
|
|
74
|
-
|
|
73
|
+
# only timeout_at moves. A per-run wait_timeout: that raises here, or
|
|
74
|
+
# returns what is no deadline, pauses the run with that error: the
|
|
75
|
+
# sweep holds the run's row lock, under which no on_exception block
|
|
76
|
+
# may run, so the exception policies do not apply.
|
|
77
|
+
def notify!(record, step, definition, notes:, now:)
|
|
78
|
+
timeout_at = notify_deadline(record, step, definition, now)
|
|
79
|
+
rescue StandardError => e
|
|
80
|
+
Waiting.resolve!(record, step, FlowControl::Outcome.pause, notes: notes, error: e)
|
|
81
|
+
else
|
|
75
82
|
step.timeout_at = timeout_at if WorkflowStep.move_deadline!(step.id, timeout_at: timeout_at).positive?
|
|
76
83
|
end
|
|
77
84
|
|
|
85
|
+
# The next deadline of a :notify wait. A per-run wait_timeout: (issue
|
|
86
|
+
# #574) is evaluated again: a Time after now is the next deadline, a
|
|
87
|
+
# duration moves it one period on as a static one does, and nil or a
|
|
88
|
+
# Time not after now leaves the wait without a deadline (it was
|
|
89
|
+
# reported once and keeps waiting).
|
|
90
|
+
def notify_deadline(record, step, definition, now)
|
|
91
|
+
return next_deadline(step.timeout_at, definition.wait_timeout, now) unless definition.dynamic_wait_timeout?
|
|
92
|
+
|
|
93
|
+
deadline = definition.resolve_wait_timeout(instance_for(record, step))
|
|
94
|
+
case deadline
|
|
95
|
+
when nil then nil
|
|
96
|
+
when Time then deadline if deadline > now
|
|
97
|
+
else next_deadline(step.timeout_at, deadline, now)
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# The workflow instance a per-run wait_timeout: is evaluated on, as the
|
|
102
|
+
# StepJob builds it for the attempt.
|
|
103
|
+
def instance_for(record, step)
|
|
104
|
+
record.workflow_klass.new(record).tap do |workflow|
|
|
105
|
+
workflow.send(:enter_step, StepContext::Attempt.new(step_id: step.id, step_name: step.step_name, attempt: step.attempt))
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
78
109
|
# The first deadline after +now+ on the wait's wait_timeout grid: one
|
|
79
110
|
# wait_timeout on when the sweep is within a period of the deadline
|
|
80
111
|
# (and for expire_wait ahead of it). A sweep that missed several
|
data/lib/pgbus/workflow.rb
CHANGED
|
@@ -111,12 +111,18 @@ module Pgbus
|
|
|
111
111
|
#
|
|
112
112
|
# SignupWorkflow.start!(user, plan: "pro") # arguments["plan"]
|
|
113
113
|
# CheckoutWorkflow.start!(order, idempotency_key: "checkout-#{order.id}")
|
|
114
|
+
# ReportWorkflow.start!(actor: "alice", reason: "monthly close")
|
|
114
115
|
#
|
|
115
|
-
# +idempotency_key+
|
|
116
|
-
#
|
|
117
|
-
#
|
|
118
|
-
|
|
119
|
-
|
|
116
|
+
# +idempotency_key+, +actor+ and +reason+ are reserved and never reach
|
|
117
|
+
# the arguments. With an idempotency_key, a second start! with the same
|
|
118
|
+
# key returns the first run (any status) with duplicate_start? true and
|
|
119
|
+
# records nothing. +actor+ (default "app") and +reason+ go on the
|
|
120
|
+
# started event, and the actor on the first step_scheduled, as on every
|
|
121
|
+
# outside verb. Raises AlreadyRunning when the subject already has an
|
|
122
|
+
# ongoing run.
|
|
123
|
+
def start!(subject = nil, idempotency_key: nil, actor: nil, reason: nil, **arguments)
|
|
124
|
+
Runner.start(self, subject: subject, arguments: arguments, idempotency_key: idempotency_key,
|
|
125
|
+
actor: actor || Runner::DEFAULT_ACTOR, reason: reason)
|
|
120
126
|
end
|
|
121
127
|
|
|
122
128
|
# The run with this workflow_id, as an instance of the class that
|
data/sig/pgbus/client.rbs
CHANGED
|
@@ -13,7 +13,7 @@ module Pgbus
|
|
|
13
13
|
def convert_archive_partitioned: (untyped queue_name, ?partition_interval: untyped, ?retention_interval: untyped, ?leading_partition: untyped) -> untyped
|
|
14
14
|
def create_fifo_index: (untyped queue_name) -> untyped
|
|
15
15
|
def create_fifo_indexes_all: () -> untyped
|
|
16
|
-
def dead_letter_physical_name: (untyped queue_name) -> untyped
|
|
16
|
+
def dead_letter_physical_name: (untyped queue_name, ?prefixed: untyped) -> untyped
|
|
17
17
|
def delete_batch: (untyped queue_name, untyped msg_ids, ?prefixed: untyped) -> untyped
|
|
18
18
|
def delete_message: (untyped queue_name, untyped msg_id, ?prefixed: untyped) -> untyped
|
|
19
19
|
def drop_queue: (untyped queue_name, ?prefixed: untyped) -> untyped
|
|
@@ -25,10 +25,12 @@ module Pgbus
|
|
|
25
25
|
def in_recovery?: () -> bool
|
|
26
26
|
def list_notify_insert_throttles: () -> untyped
|
|
27
27
|
def list_queues: () -> untyped
|
|
28
|
-
def
|
|
29
|
-
def
|
|
30
|
-
def
|
|
31
|
-
def
|
|
28
|
+
def locate_message: (untyped queue_name, msg_id: untyped, ?job_id: untyped, ?prefixed: untyped) -> String?
|
|
29
|
+
def locate_messages: (untyped queue_name, Array[[untyped, untyped]] messages, ?prefixed: untyped) -> Hash[Integer, String]
|
|
30
|
+
def message_archived?: (untyped queue_name, msg_id: untyped, ?prefixed: untyped) -> bool?
|
|
31
|
+
def message_exists?: (untyped queue_name, ?msg_id: untyped, ?uniqueness_key: untyped, ?prefixed: untyped) -> bool?
|
|
32
|
+
def message_in_queue?: (untyped queue_name, msg_id: untyped, ?prefixed: untyped) -> bool?
|
|
33
|
+
def message_with_job_id?: (untyped queue_name, job_id: untyped, ?prefixed: untyped) -> bool?
|
|
32
34
|
def metrics: (?untyped queue_name) -> untyped
|
|
33
35
|
def move_to_dead_letter: (untyped queue_name, untyped message, ?headers: untyped) -> untyped
|
|
34
36
|
def notify_enabled?: (untyped queue_name) -> bool
|
data/sig/pgbus.rbs
CHANGED
|
@@ -56,6 +56,49 @@ module Pgbus
|
|
|
56
56
|
end
|
|
57
57
|
end
|
|
58
58
|
|
|
59
|
+
# Partial: only the readers a workflow step's guards and body use to see
|
|
60
|
+
# its signal (issue #572), and a step definition's wait_timeout: (issue
|
|
61
|
+
# #574). The rest of Workflow is not covered by spec/pgbus/rbs_spec.rb yet.
|
|
62
|
+
class Workflow
|
|
63
|
+
include Instance
|
|
64
|
+
|
|
65
|
+
class Error < Pgbus::Error
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# A step reader (woken?, signal_ready?, ...) called outside a step.
|
|
69
|
+
class NotInStep < Error
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
module Instance
|
|
73
|
+
# The Pgbus::WorkflowSignal a wait_for: step took, or nil when its wait timed out.
|
|
74
|
+
def received_signal: () -> untyped
|
|
75
|
+
# The body runs because the wait timed out (on_timeout: :run).
|
|
76
|
+
def timed_out?: () -> bool
|
|
77
|
+
# This attempt holds a signal before its gate: signal! woke it, or an
|
|
78
|
+
# earlier attempt took one and reattempted or paused.
|
|
79
|
+
def woken?: () -> bool
|
|
80
|
+
# The gate runs this attempt with a signal: the held one, or a pending
|
|
81
|
+
# one its wait_for: matcher takes.
|
|
82
|
+
def signal_ready?: () -> bool
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# One declared step (klass.workflow_steps.fetch(:name)): its wait_timeout:.
|
|
86
|
+
class StepDefinition
|
|
87
|
+
# A static wait_timeout: in seconds; nil without one, or for a per-run one.
|
|
88
|
+
def wait_timeout: () -> Numeric?
|
|
89
|
+
# A per-run wait_timeout: as declared: a method name or a lambda.
|
|
90
|
+
def wait_timeout_callable: () -> (Symbol | Proc)?
|
|
91
|
+
# wait_timeout: is a method name or a lambda, evaluated per run.
|
|
92
|
+
def dynamic_wait_timeout?: () -> bool
|
|
93
|
+
# The timeout_at of the step parking at +now+ on +workflow+; nil for no timeout.
|
|
94
|
+
# +now+ and the result are a Time or an ActiveSupport::TimeWithZone (Time.current
|
|
95
|
+
# in an app with a time zone), which sig/ does not declare: untyped.
|
|
96
|
+
def timeout_at_for: (Workflow workflow, untyped now) -> untyped
|
|
97
|
+
# What a per-run wait_timeout: returns on +workflow+: a deadline, seconds from now, or nil.
|
|
98
|
+
def resolve_wait_timeout: (Workflow workflow) -> (Time | Numeric)?
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
59
102
|
def self.configuration: () -> Configuration
|
|
60
103
|
def self.configuration_snapshot: () -> Configuration::Snapshot
|
|
61
104
|
def self.configure: () { (Configuration) -> void } -> Configuration
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: pgbus
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.21.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Mikael Henriksson
|
|
@@ -588,6 +588,7 @@ files:
|
|
|
588
588
|
- lib/pgbus/workflow/removed_step.rb
|
|
589
589
|
- lib/pgbus/workflow/runner.rb
|
|
590
590
|
- lib/pgbus/workflow/signal_matcher.rb
|
|
591
|
+
- lib/pgbus/workflow/signal_peek.rb
|
|
591
592
|
- lib/pgbus/workflow/signals.rb
|
|
592
593
|
- lib/pgbus/workflow/states.rb
|
|
593
594
|
- lib/pgbus/workflow/step_context.rb
|