riverqueue 0.13.0 → 0.14.0
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 +37 -11
- data/README.md +83 -14
- data/docs/README.md +160 -30
- data/docs/conformance.md +11 -11
- data/docs/migrations.md +16 -16
- data/docs/testing.md +1 -1
- data/lib/client.rb +61 -6
- data/lib/client_runtime.rb +273 -35
- data/lib/config.rb +61 -9
- data/lib/driver/job_row_decoder.rb +2 -2
- data/lib/driver/notification_listener.rb +61 -0
- data/lib/driver/postgres_capabilities.rb +1 -1
- data/lib/driver/runtime.rb +214 -52
- data/lib/driver.rb +1 -0
- data/lib/insert_opts.rb +1 -1
- data/lib/job.rb +4 -4
- data/lib/job_persisted_logging/plugin.rb +3 -2
- data/lib/migrator.rb +1 -1
- data/lib/periodic_cron.rb +5 -4
- data/lib/periodic_job.rb +14 -3
- data/lib/resumable.rb +24 -1
- data/lib/worker.rb +32 -2
- data/migration/manifest.json +5 -5
- data/migration/postgresql/main/007_notification_outbox_sqlite_jsonb_and_sql_cleanup.down.sql +1 -1
- data/migration/postgresql/main/007_notification_outbox_sqlite_jsonb_and_sql_cleanup.up.sql +1 -1
- data/migration/postgresql/main/008_job_id_autoincrement.down.sql +1 -1
- data/migration/postgresql/main/008_job_id_autoincrement.up.sql +1 -1
- data/migration/sqlite/main/008_job_id_autoincrement.up.sql +1 -1
- data/sig/client.rbs +4 -1
- data/sig/driver.rbs +40 -5
- data/sig/runtime.rbs +52 -4
- metadata +4 -3
data/lib/resumable.rb
CHANGED
|
@@ -11,6 +11,7 @@ module River
|
|
|
11
11
|
attr_accessor :completed_step
|
|
12
12
|
attr_reader :cursors
|
|
13
13
|
attr_accessor :cursors_dirty
|
|
14
|
+
attr_reader :pending_cursor_steps
|
|
14
15
|
attr_accessor :resume_matched
|
|
15
16
|
attr_reader :resume_step
|
|
16
17
|
attr_accessor :step_name
|
|
@@ -24,6 +25,8 @@ module River
|
|
|
24
25
|
@step_name = nil
|
|
25
26
|
|
|
26
27
|
@resume_matched = @resume_step.to_s.empty?
|
|
28
|
+
# Step markers may accompany stale cursors from older clients.
|
|
29
|
+
@pending_cursor_steps = @resume_matched ? @cursors.keys.sort : []
|
|
27
30
|
end
|
|
28
31
|
|
|
29
32
|
def register(name)
|
|
@@ -37,6 +40,9 @@ module River
|
|
|
37
40
|
# Internal runtime boundary: attach progress only to attempts that did not
|
|
38
41
|
# complete, matching River Go's persisted metadata format.
|
|
39
42
|
def __capture_resumable_metadata!
|
|
43
|
+
# Keep missing cursor steps reachable when the worker restores them.
|
|
44
|
+
return unless @resumable_state.pending_cursor_steps.empty?
|
|
45
|
+
|
|
40
46
|
if @resumable_state.cursors_dirty
|
|
41
47
|
@metadata_updates[RESUMABLE_CURSOR_METADATA_KEY] = @resumable_state.cursors.empty? ? nil : @resumable_state.cursors.dup
|
|
42
48
|
end
|
|
@@ -49,6 +55,9 @@ module River
|
|
|
49
55
|
# Internal runtime boundary: validate that the recorded resume point still
|
|
50
56
|
# exists in the worker after it has returned.
|
|
51
57
|
def __finish_resumable_work!
|
|
58
|
+
if (pending = @resumable_state.pending_cursor_steps.first)
|
|
59
|
+
raise Error, "resumable cursor step #{pending.inspect} not found in worker"
|
|
60
|
+
end
|
|
52
61
|
if @resumable_state.resume_step && !@resumable_state.resume_matched
|
|
53
62
|
raise Error, "resumable step #{@resumable_state.resume_step.inspect} not found in worker"
|
|
54
63
|
end
|
|
@@ -56,12 +65,22 @@ module River
|
|
|
56
65
|
|
|
57
66
|
# Immediately checkpoints the current step and cursor progress. Wrap the
|
|
58
67
|
# call in Driver#transaction alongside application writes when an atomic
|
|
59
|
-
# checkpoint is needed.
|
|
68
|
+
# checkpoint is needed. When resuming cursor-only progress, reach its saved
|
|
69
|
+
# cursor step before checkpointing another step.
|
|
70
|
+
#
|
|
71
|
+
# Commit the transaction before the step block returns
|
|
72
|
+
# successfully, and let transaction and commit errors propagate out of it.
|
|
73
|
+
# A successful block marks the step complete even if an enclosing transaction
|
|
74
|
+
# later rolls back.
|
|
60
75
|
def resumable_checkpoint(cursor: RESUMABLE_CURSOR_UNSET)
|
|
61
76
|
step_name = @resumable_state.step_name
|
|
62
77
|
raise Error, "resumable step can only be persisted inside a resumable step" unless step_name
|
|
63
78
|
raise Error, "job must be running" unless row.state == JOB_STATE_RUNNING
|
|
64
79
|
|
|
80
|
+
if (pending = @resumable_state.pending_cursor_steps.first)
|
|
81
|
+
raise Error, "resumable checkpoint cannot precede saved cursor step #{pending.inspect}"
|
|
82
|
+
end
|
|
83
|
+
|
|
65
84
|
cursors = @resumable_state.cursors.dup
|
|
66
85
|
cursors[step_name] = JSON.parse(JSON.generate(cursor)) unless cursor.equal?(RESUMABLE_CURSOR_UNSET)
|
|
67
86
|
updates = {
|
|
@@ -117,6 +136,9 @@ module River
|
|
|
117
136
|
private def run_resumable_step(name, cursor:, default:)
|
|
118
137
|
raise Error, "resumable steps cannot be nested" if @resumable_state.step_name
|
|
119
138
|
raise ArgumentError, "resumable step name must be non-empty" if name.empty?
|
|
139
|
+
if !cursor && @resumable_state.pending_cursor_steps.include?(name)
|
|
140
|
+
raise Error, "resumable cursor step #{name.inspect} requires a cursor step"
|
|
141
|
+
end
|
|
120
142
|
@resumable_state.register(name)
|
|
121
143
|
|
|
122
144
|
unless @resumable_state.resume_matched
|
|
@@ -132,6 +154,7 @@ module River
|
|
|
132
154
|
@resumable_state.step_name = name
|
|
133
155
|
begin
|
|
134
156
|
value = (cursor && @resumable_state.cursors.key?(name)) ? @resumable_state.cursors[name] : default
|
|
157
|
+
@resumable_state.pending_cursor_steps.delete(name) if cursor
|
|
135
158
|
result = cursor ? yield(value) : yield
|
|
136
159
|
@resumable_state.completed_step = name
|
|
137
160
|
if cursor && @resumable_state.cursors.key?(name)
|
data/lib/worker.rb
CHANGED
|
@@ -12,8 +12,18 @@ module River
|
|
|
12
12
|
#
|
|
13
13
|
# With one argument, the kind is read from +worker.kind+ or
|
|
14
14
|
# +worker.class.kind+. Pass a kind and worker separately to override it.
|
|
15
|
-
#
|
|
16
|
-
|
|
15
|
+
# Alternatively, pass a kind and a block that receives a River::Job on each
|
|
16
|
+
# attempt. Block workers use the client's retry and timeout policies.
|
|
17
|
+
# Supply a worker or a block, not both. Kinds and aliases accept symbols or
|
|
18
|
+
# strings.
|
|
19
|
+
def add(kind_or_worker, worker = nil, aliases: [], &block)
|
|
20
|
+
if block
|
|
21
|
+
raise ArgumentError, "use a worker or a block, not both" unless worker.nil?
|
|
22
|
+
raise ArgumentError, "block workers require a string or symbol kind" unless kind_or_worker.is_a?(String) || kind_or_worker.is_a?(Symbol)
|
|
23
|
+
|
|
24
|
+
worker = BlockWorker.new(block)
|
|
25
|
+
end
|
|
26
|
+
|
|
17
27
|
if worker
|
|
18
28
|
kind = kind_or_worker.to_s
|
|
19
29
|
else
|
|
@@ -54,11 +64,29 @@ module River
|
|
|
54
64
|
def kinds
|
|
55
65
|
@workers.keys.freeze
|
|
56
66
|
end
|
|
67
|
+
|
|
68
|
+
# Adapts a registered block to the runtime's worker interface.
|
|
69
|
+
class BlockWorker
|
|
70
|
+
def initialize(work_func)
|
|
71
|
+
@work_func = work_func
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def work(job)
|
|
75
|
+
@work_func.call(job)
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
private_constant :BlockWorker
|
|
57
79
|
end
|
|
58
80
|
|
|
59
81
|
# A job being worked, with access to its persisted row and attempt-local
|
|
60
82
|
# metadata changes.
|
|
61
83
|
class Job
|
|
84
|
+
# Internal runtime hint; persisted state determines whether completion committed.
|
|
85
|
+
attr_accessor :__completion_attempted
|
|
86
|
+
|
|
87
|
+
# Internal snapshot retained only after transactional completion commits.
|
|
88
|
+
attr_accessor :__completion_snapshot
|
|
89
|
+
|
|
62
90
|
# Client working this job.
|
|
63
91
|
attr_reader :client
|
|
64
92
|
|
|
@@ -67,6 +95,8 @@ module River
|
|
|
67
95
|
|
|
68
96
|
def initialize(client, row)
|
|
69
97
|
@client = client
|
|
98
|
+
@__completion_attempted = false
|
|
99
|
+
@__completion_snapshot = nil
|
|
70
100
|
@logger = nil
|
|
71
101
|
@metadata_updates = {}
|
|
72
102
|
@row = row
|
data/migration/manifest.json
CHANGED
|
@@ -12,10 +12,10 @@
|
|
|
12
12
|
"postgresql/main/005_migration_unique_client.up.sql": "b760f487152c7d92102869d46b8a64dc1e2094d5675e690ffbe52a747eee8431",
|
|
13
13
|
"postgresql/main/006_bulk_unique.down.sql": "726483f6e5aa7dd02cdd974cd7bf716973a8d0a97ba6dbc5dc5304aaf54c7ad7",
|
|
14
14
|
"postgresql/main/006_bulk_unique.up.sql": "3b133f7ce4662d3dc8bd4a57628e0e116a300b2635a79315557aa1369849f0fb",
|
|
15
|
-
"postgresql/main/007_notification_outbox_sqlite_jsonb_and_sql_cleanup.down.sql": "
|
|
16
|
-
"postgresql/main/007_notification_outbox_sqlite_jsonb_and_sql_cleanup.up.sql": "
|
|
17
|
-
"postgresql/main/008_job_id_autoincrement.down.sql": "
|
|
18
|
-
"postgresql/main/008_job_id_autoincrement.up.sql": "
|
|
15
|
+
"postgresql/main/007_notification_outbox_sqlite_jsonb_and_sql_cleanup.down.sql": "2771765becc5baa0a8af4406cb4d58ea6d3fb0ebdbf72a0c23ccc72da623caeb",
|
|
16
|
+
"postgresql/main/007_notification_outbox_sqlite_jsonb_and_sql_cleanup.up.sql": "af01339fcb1687de1f768a570b6ad1e51d23300082aed60440f6a662a0e39d85",
|
|
17
|
+
"postgresql/main/008_job_id_autoincrement.down.sql": "678b3b02deb2f798c3fda3a73c974fc1fe48c6b88688b94f0f7700132b30626f",
|
|
18
|
+
"postgresql/main/008_job_id_autoincrement.up.sql": "678b3b02deb2f798c3fda3a73c974fc1fe48c6b88688b94f0f7700132b30626f",
|
|
19
19
|
"sqlite/main/001_create_river_migration.down.sql": "34c87dc594bf7520bc3ae69f6f0da8d2d9a472616ab38b37e63d4e3838da06d2",
|
|
20
20
|
"sqlite/main/001_create_river_migration.up.sql": "d15597cb0bb884fb0727d2a29ad8313842708b55fd561a5fe62e37aad5f34298",
|
|
21
21
|
"sqlite/main/002_initial_schema.down.sql": "900508ba08d0ca3c8451eb2854cd9ab837166ef55736393524253b6228438470",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"sqlite/main/007_notification_outbox_sqlite_jsonb_and_sql_cleanup.down.sql": "55bffeb528b40dffc0cbec2f22d1463aef37a8b3d7977f83729cc505bb77c745",
|
|
32
32
|
"sqlite/main/007_notification_outbox_sqlite_jsonb_and_sql_cleanup.up.sql": "441a05e1d9aa4f151877ccf725b0b0a86f27013442297d4b621c05676270d0b0",
|
|
33
33
|
"sqlite/main/008_job_id_autoincrement.down.sql": "04871283fe5d4cab4ac70da28d8509aa7ba765994d528c2dcc7ebe0ee596710c",
|
|
34
|
-
"sqlite/main/008_job_id_autoincrement.up.sql": "
|
|
34
|
+
"sqlite/main/008_job_id_autoincrement.up.sql": "3ce6d941f4c434adbd87e69089fa5e99b6047e5b51e611c9845e1d0d3c080e0f"
|
|
35
35
|
},
|
|
36
36
|
"source": "riverdriver/"
|
|
37
37
|
}
|
data/migration/postgresql/main/007_notification_outbox_sqlite_jsonb_and_sql_cleanup.down.sql
CHANGED
|
@@ -47,7 +47,7 @@ ALTER TABLE /* TEMPLATE: schema */river_queue
|
|
|
47
47
|
--
|
|
48
48
|
-- SQLite JSONB conversion rollback.
|
|
49
49
|
--
|
|
50
|
-
-- No-op.
|
|
50
|
+
-- No-op. Postgres already stores River JSON columns as jsonb.
|
|
51
51
|
|
|
52
52
|
--
|
|
53
53
|
-- Notification outbox rollback.
|
|
@@ -16,7 +16,7 @@ CREATE INDEX river_notification_topic_id_idx ON /* TEMPLATE: schema */river_noti
|
|
|
16
16
|
--
|
|
17
17
|
-- SQLite JSONB conversion.
|
|
18
18
|
--
|
|
19
|
-
-- No-op.
|
|
19
|
+
-- No-op. Postgres already stores River JSON columns as jsonb.
|
|
20
20
|
|
|
21
21
|
--
|
|
22
22
|
-- SQL cleanup.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
-- Rebuild river_job so automatically generated IDs are never reused after the
|
|
2
|
-
-- job holding the largest ID is deleted. Unlike
|
|
2
|
+
-- job holding the largest ID is deleted. Unlike Postgres sequences, SQLite's
|
|
3
3
|
-- default ROWID allocator may otherwise reuse that deleted ID.
|
|
4
4
|
|
|
5
5
|
-- Rebuilding river_job would discard schema installed by River Pro. Check
|
data/sig/client.rbs
CHANGED
|
@@ -15,6 +15,7 @@ module River
|
|
|
15
15
|
|
|
16
16
|
def initialize: (_Driver driver, ?config: Config?) -> void
|
|
17
17
|
def __finish_claimed_job: (JobRow, ?Exception?) -> untyped
|
|
18
|
+
def __insert_with_default_scheduled_at: (jobArgs, InsertOpts, Time?) -> JobInsertResult
|
|
18
19
|
def __perform_job: (Integer, ?allow_scheduled: bool) -> untyped
|
|
19
20
|
def __interrupt_workers: () -> untyped
|
|
20
21
|
def __runtime_healthy?: () -> bool
|
|
@@ -24,6 +25,7 @@ module River
|
|
|
24
25
|
?scheduled_at: Time?, ?state: jobStateInitialInput?, ?tags: Array[String]?, ?unique_opts: UniqueOpts?) -> JobInsertResult
|
|
25
26
|
def insert_many: (Array[jobArgs | InsertManyParams]) -> Array[JobInsertResult]
|
|
26
27
|
def job_cancel: (Integer) -> JobRow
|
|
28
|
+
def job_complete_tx: (Job) -> JobRow
|
|
27
29
|
def job_delete: (Integer) -> JobRow
|
|
28
30
|
def job_delete_many: (?JobListParams?, ?after: untyped, ?after_id: untyped,
|
|
29
31
|
?ids: untyped, ?kinds: untyped, ?limit: untyped, ?metadata: untyped, ?priorities: untyped,
|
|
@@ -46,6 +48,7 @@ module River
|
|
|
46
48
|
def queue_remove: (String | Symbol) -> self
|
|
47
49
|
def queue_resume: (String | Symbol) -> bool
|
|
48
50
|
def queue_update: (String | Symbol, metadata: Hash[untyped, untyped]) -> Queue
|
|
51
|
+
def request_resign: () -> nil
|
|
49
52
|
def start: () -> self
|
|
50
53
|
def started?: () -> bool
|
|
51
54
|
def stop: (?wait: bool) -> self
|
|
@@ -60,7 +63,7 @@ module River
|
|
|
60
63
|
TAG_RE: Regexp
|
|
61
64
|
|
|
62
65
|
private def insert_and_check_unique_job: (Driver::JobInsertParams) -> JobInsertResult
|
|
63
|
-
private def make_insert_params: (jobArgs, InsertOpts) -> Driver::JobInsertParams
|
|
66
|
+
private def make_insert_params: (jobArgs, InsertOpts, ?Time?) -> Driver::JobInsertParams
|
|
64
67
|
private def make_unique_key_and_bitmask: (Driver::JobInsertParams, UniqueOpts) -> [String, String]
|
|
65
68
|
private def run_insert_plugins: (Array[Driver::JobInsertParams]) { () -> Array[JobInsertResult] } -> Array[JobInsertResult]
|
|
66
69
|
private def truncate_time: (Time, Integer | Rational) -> Time
|
data/sig/driver.rbs
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
module River
|
|
2
2
|
interface _Driver
|
|
3
|
+
def after_commit: () { () -> void } -> void
|
|
3
4
|
def respond_to?: (Symbol, ?bool) -> bool
|
|
5
|
+
def in_transaction?: () -> bool
|
|
4
6
|
def init_driver: () -> void
|
|
5
7
|
def migration_backend: () -> Symbol
|
|
6
8
|
def migration_connection: [A] () { (untyped) -> A } -> A
|
|
@@ -13,11 +15,11 @@ module River
|
|
|
13
15
|
def job_get_available: (queue: String, max: Integer, attempted_by: String, ?kinds: Array[String]?, ?now: Time) -> Array[JobRow]
|
|
14
16
|
def job_claim: (id: Integer, attempted_by: String, ?allow_scheduled: bool, ?now: Time) -> JobRow?
|
|
15
17
|
def job_get_cancelled_ids: (Array[Integer]) -> Array[Integer]
|
|
16
|
-
def job_complete: (id: Integer, finalized_at: Time, ?metadata: Hash[untyped, untyped]?, ?now: Time) -> (JobRow | :cancelled)?
|
|
18
|
+
def job_complete: (id: Integer, finalized_at: Time, ?expected_job: JobRow?, ?metadata: Hash[untyped, untyped]?, ?now: Time) -> (JobRow | :cancelled)?
|
|
17
19
|
def job_get_by_kind_and_unique_properties: (Driver::JobGetByKindAndUniquePropertiesParam) -> JobRow?
|
|
18
20
|
def job_insert: (Driver::JobInsertParams) -> [JobRow, bool]
|
|
19
21
|
def job_insert_many: (Array[Driver::JobInsertParams]) -> Array[[JobRow, bool]]
|
|
20
|
-
def job_metadata_merge: (Integer, Hash[untyped, untyped]) -> JobRow?
|
|
22
|
+
def job_metadata_merge: (Integer, Hash[untyped, untyped], ?JobRow?) -> JobRow?
|
|
21
23
|
def job_rescue_stuck: (**untyped) -> Integer
|
|
22
24
|
def job_retry: (Integer, ?now: Time) -> JobRow?
|
|
23
25
|
def job_schedule: (?now: Time, ?max: Integer) -> Integer
|
|
@@ -26,13 +28,17 @@ module River
|
|
|
26
28
|
def leader_acquire: (String, ?ttl: Integer, ?now: Time) -> bool
|
|
27
29
|
def leader_release: (String) -> untyped
|
|
28
30
|
def leader_renew: (String, ?ttl: Integer, ?now: Time) -> bool
|
|
31
|
+
def normalize_time: (Time) -> Time
|
|
29
32
|
def notification_delete_before: (horizon: Time, ?max: Integer) -> Integer
|
|
33
|
+
def notification_listener: () -> untyped
|
|
34
|
+
def request_resign: () -> nil
|
|
30
35
|
def queue_get: (String) -> Queue?
|
|
31
36
|
def queue_list: (?max: Integer) -> Array[Queue]
|
|
32
37
|
def queue_pause: (String, ?now: Time) -> Array[Queue]
|
|
33
38
|
def queue_resume: (String, ?now: Time) -> Array[Queue]
|
|
34
39
|
def queue_update: (String, metadata: Hash[untyped, untyped], ?now: Time) -> Queue?
|
|
35
40
|
def queue_upsert: (String, ?metadata: Hash[untyped, untyped], ?now: Time) -> Queue?
|
|
41
|
+
def time_precision: () -> Rational
|
|
36
42
|
def transaction: [T] () { () -> T } -> T
|
|
37
43
|
|
|
38
44
|
# this set of methods is used only in tests
|
|
@@ -56,6 +62,25 @@ module River
|
|
|
56
62
|
def finish: (JobRow) -> JobRow
|
|
57
63
|
end
|
|
58
64
|
|
|
65
|
+
module NotificationListener
|
|
66
|
+
TOPICS: Array[String]
|
|
67
|
+
class Postgres
|
|
68
|
+
@connection: untyped
|
|
69
|
+
@channels: Hash[String, String]
|
|
70
|
+
def initialize: (untyped, String) -> void
|
|
71
|
+
def close: () -> untyped
|
|
72
|
+
def poll: (Float | Integer) -> Array[untyped]
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
class SQLite
|
|
76
|
+
@query: untyped
|
|
77
|
+
@last_id: Integer
|
|
78
|
+
def initialize: (untyped) -> void
|
|
79
|
+
def close: () -> nil
|
|
80
|
+
def poll: (Float | Integer) -> Array[untyped]
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
59
84
|
class PostgresCapabilities
|
|
60
85
|
attr_reader supports_listen_notify: bool
|
|
61
86
|
attr_reader unique_insert_mode: :metadata_nonce | :returning_old | :xmax
|
|
@@ -103,10 +128,11 @@ module River
|
|
|
103
128
|
def runtime_decode_postgres_job: (untyped) -> JobRow
|
|
104
129
|
@postgres_capabilities_cache: PostgresCapabilities::Cache
|
|
105
130
|
def init_driver: () -> void
|
|
131
|
+
def normalize_time: (Time) -> Time
|
|
106
132
|
def postgres_capabilities: () -> PostgresCapabilities
|
|
107
133
|
def postgres_notify_insert: (Array[JobInsertParams]) -> void
|
|
108
134
|
def job_get_cancelled_ids: (Array[Integer]) -> Array[Integer]
|
|
109
|
-
def job_complete: (id: untyped, finalized_at: untyped, ?metadata: untyped, ?now: untyped) -> untyped
|
|
135
|
+
def job_complete: (id: untyped, finalized_at: untyped, ?expected_job: untyped, ?metadata: untyped, ?now: untyped) -> untyped
|
|
110
136
|
def job_cancel: (untyped, ?now: untyped) -> untyped
|
|
111
137
|
def job_delete: (untyped) -> untyped
|
|
112
138
|
def job_delete_finalized: (retention: untyped, ?now: untyped, ?max: untyped) -> untyped
|
|
@@ -116,7 +142,7 @@ module River
|
|
|
116
142
|
def job_claim: (id: untyped, attempted_by: untyped, ?allow_scheduled: untyped, ?now: untyped) -> untyped
|
|
117
143
|
private def runtime_claim_jobs: (untyped, untyped, untyped, untyped) -> untyped
|
|
118
144
|
def job_list: (?untyped) -> untyped
|
|
119
|
-
def job_metadata_merge: (untyped, untyped) -> untyped
|
|
145
|
+
def job_metadata_merge: (untyped, untyped, ?untyped) -> untyped
|
|
120
146
|
def job_rescue_stuck: (horizon: untyped, retry_policy: untyped, ?now: untyped, ?max: untyped, ?logger: untyped, ?rescue_if: untyped) -> untyped
|
|
121
147
|
def job_retry: (untyped, ?now: untyped) -> untyped
|
|
122
148
|
def job_schedule: (?now: untyped, ?max: untyped) -> untyped
|
|
@@ -126,6 +152,8 @@ module River
|
|
|
126
152
|
def leader_release: (untyped) -> untyped
|
|
127
153
|
def leader_renew: (untyped, ?ttl: untyped, ?now: untyped) -> untyped
|
|
128
154
|
def notification_delete_before: (horizon: untyped, ?max: untyped) -> untyped
|
|
155
|
+
def notification_listener: () -> untyped
|
|
156
|
+
def request_resign: () -> nil
|
|
129
157
|
def queue_get: (untyped) -> untyped
|
|
130
158
|
def queue_list: (?max: untyped) -> untyped
|
|
131
159
|
def queue_pause: (untyped, ?now: untyped) -> untyped
|
|
@@ -133,6 +161,8 @@ module River
|
|
|
133
161
|
def queue_update: (untyped, metadata: untyped, ?now: untyped) -> untyped
|
|
134
162
|
def queue_upsert: (untyped, ?metadata: untyped, ?now: untyped) -> untyped
|
|
135
163
|
|
|
164
|
+
def time_precision: () -> Rational
|
|
165
|
+
|
|
136
166
|
private
|
|
137
167
|
|
|
138
168
|
def job_get_by_id: (untyped) -> untyped
|
|
@@ -142,14 +172,18 @@ module River
|
|
|
142
172
|
def runtime_cursor_clause: (untyped) -> String
|
|
143
173
|
def runtime_execute: (String) -> untyped
|
|
144
174
|
def runtime_in_clause: (untyped, untyped) -> untyped
|
|
175
|
+
def runtime_job_attempt_predicate: (untyped) -> String
|
|
145
176
|
def runtime_job_list_without_params: () -> untyped
|
|
146
177
|
def runtime_job_list: (JobListParams, ?for_delete: bool) -> Array[JobRow]
|
|
147
178
|
def runtime_job_rows: (String) -> untyped
|
|
148
179
|
def runtime_json: (untyped) -> untyped
|
|
180
|
+
def runtime_legacy_subtransactions?: () -> bool
|
|
149
181
|
def runtime_merge_metadata: (untyped) -> untyped
|
|
150
182
|
def runtime_metadata_equals: (untyped, untyped) -> untyped
|
|
151
183
|
def runtime_nullable_time: (untyped) -> untyped
|
|
152
184
|
def runtime_notify: (String, untyped) -> untyped
|
|
185
|
+
def notification_query: (String) -> untyped
|
|
186
|
+
def runtime_notification_connection: () -> untyped
|
|
153
187
|
def sqlite_insert_nonces: (Array[JobInsertParams]) -> Array[String]
|
|
154
188
|
def runtime_parse_json: (untyped) -> untyped
|
|
155
189
|
def runtime_parse_time: (untyped) -> untyped
|
|
@@ -160,10 +194,11 @@ module River
|
|
|
160
194
|
def runtime_quote: (untyped) -> String
|
|
161
195
|
def runtime_rescue_retry: (untyped, untyped, untyped, untyped, untyped) -> Time
|
|
162
196
|
def runtime_returning_ids: (untyped) -> untyped
|
|
197
|
+
def runtime_schedule_postgres: (Time, Integer) -> Array[String]
|
|
198
|
+
def runtime_schedule_sqlite: (Time, Integer) -> Array[String]
|
|
163
199
|
def runtime_state: (untyped) -> untyped
|
|
164
200
|
def runtime_tag_contains: (untyped) -> untyped
|
|
165
201
|
def runtime_time: (untyped) -> untyped
|
|
166
|
-
def runtime_unique_violation_class: () -> singleton(Exception)
|
|
167
202
|
def runtime_update_value: (untyped, untyped) -> untyped
|
|
168
203
|
def runtime_value: (untyped, untyped) -> untyped
|
|
169
204
|
def transaction: () { () -> untyped } -> untyped
|
data/sig/runtime.rbs
CHANGED
|
@@ -77,21 +77,32 @@ module River
|
|
|
77
77
|
@workers: Hash[String, untyped]
|
|
78
78
|
def initialize: () -> void
|
|
79
79
|
def add: (untyped, ?untyped, ?aliases: Array[untyped]) -> self
|
|
80
|
+
| (String | Symbol, ?aliases: Array[untyped]) { (Job) -> untyped } -> self
|
|
80
81
|
def []: (String | Symbol) -> untyped
|
|
81
82
|
def fetch: (String | Symbol) -> untyped
|
|
82
83
|
| (String | Symbol, untyped) -> untyped
|
|
83
84
|
| (String | Symbol) { (String) -> untyped } -> untyped
|
|
84
85
|
def include?: (String | Symbol) -> bool
|
|
85
86
|
def kinds: () -> Array[String]
|
|
87
|
+
|
|
88
|
+
class BlockWorker
|
|
89
|
+
@work_func: ^(Job) -> untyped
|
|
90
|
+
def initialize: (^(Job) -> untyped) -> void
|
|
91
|
+
def work: (Job) -> untyped
|
|
92
|
+
end
|
|
86
93
|
end
|
|
87
94
|
|
|
88
95
|
class Job
|
|
89
96
|
RESUMABLE_CURSOR_UNSET: Object
|
|
97
|
+
@__completion_attempted: bool
|
|
98
|
+
@__completion_snapshot: JobRow?
|
|
90
99
|
@client: Client
|
|
91
100
|
@logger: untyped
|
|
92
101
|
@metadata_updates: Hash[String, untyped]
|
|
93
102
|
@resumable_state: ResumableState
|
|
94
103
|
@row: JobRow
|
|
104
|
+
attr_accessor __completion_attempted: bool
|
|
105
|
+
attr_accessor __completion_snapshot: JobRow?
|
|
95
106
|
attr_reader client: Client
|
|
96
107
|
attr_reader row: JobRow
|
|
97
108
|
def initialize: (Client, JobRow) -> void
|
|
@@ -126,6 +137,7 @@ module River
|
|
|
126
137
|
attr_accessor completed_step: String?
|
|
127
138
|
attr_reader cursors: Hash[String, untyped]
|
|
128
139
|
attr_accessor cursors_dirty: bool
|
|
140
|
+
attr_reader pending_cursor_steps: Array[String]
|
|
129
141
|
attr_accessor resume_matched: bool
|
|
130
142
|
attr_reader resume_step: String?
|
|
131
143
|
attr_accessor step_name: String?
|
|
@@ -152,15 +164,30 @@ module River
|
|
|
152
164
|
def resolved_fetch_poll_interval: (Config) -> Float
|
|
153
165
|
end
|
|
154
166
|
|
|
167
|
+
class DefaultClientID
|
|
168
|
+
HOSTNAME_MAX_LENGTH: Integer
|
|
169
|
+
@mutex: Mutex
|
|
170
|
+
@state: Hash[Integer, String]?
|
|
171
|
+
def initialize: () -> void
|
|
172
|
+
def value: () -> String
|
|
173
|
+
|
|
174
|
+
private
|
|
175
|
+
|
|
176
|
+
def generate: (Integer) -> String
|
|
177
|
+
end
|
|
178
|
+
|
|
155
179
|
class Config
|
|
180
|
+
@poll_only: bool
|
|
181
|
+
attr_reader poll_only: bool
|
|
156
182
|
@cancelled_job_retention_period: Float?
|
|
157
183
|
@completed_job_retention_period: Float?
|
|
184
|
+
@default_id: DefaultClientID
|
|
158
185
|
@discarded_job_retention_period: Float?
|
|
159
186
|
@error_handler: untyped
|
|
160
187
|
@fetch_cooldown: Float
|
|
161
188
|
@fetch_only_known_kinds: bool
|
|
162
189
|
@fetch_poll_interval: Float
|
|
163
|
-
@id: String
|
|
190
|
+
@id: String?
|
|
164
191
|
@job_timeout: Float?
|
|
165
192
|
@leader_election_disabled: bool
|
|
166
193
|
@logger: untyped
|
|
@@ -178,7 +205,6 @@ module River
|
|
|
178
205
|
attr_reader fetch_cooldown: Float
|
|
179
206
|
attr_reader fetch_only_known_kinds: bool
|
|
180
207
|
attr_reader fetch_poll_interval: Float
|
|
181
|
-
attr_reader id: String
|
|
182
208
|
attr_reader job_timeout: Float?
|
|
183
209
|
attr_reader leader_election_disabled: bool
|
|
184
210
|
attr_reader logger: untyped
|
|
@@ -191,13 +217,16 @@ module River
|
|
|
191
217
|
|
|
192
218
|
def initialize: (?queues: untyped, ?workers: untyped, ?id: untyped,
|
|
193
219
|
?fetch_cooldown: untyped, ?fetch_only_known_kinds: bool, ?fetch_poll_interval: untyped, ?job_timeout: untyped,
|
|
194
|
-
?leader_election_disabled: bool,
|
|
220
|
+
?leader_election_disabled: bool, ?poll_only: bool,
|
|
195
221
|
?retry_policy: untyped, ?error_handler: untyped, ?plugins: untyped,
|
|
196
222
|
?maintenance_services: untyped, ?periodic_jobs: untyped,
|
|
197
223
|
?cancelled_job_retention_period: untyped, ?completed_job_retention_period: untyped,
|
|
198
224
|
?discarded_job_retention_period: untyped, ?logger: untyped) -> void
|
|
225
|
+
def id: () -> String
|
|
199
226
|
def with: (**untyped) -> Config
|
|
200
227
|
|
|
228
|
+
def adopt_default_id: (DefaultClientID) -> void
|
|
229
|
+
|
|
201
230
|
private
|
|
202
231
|
|
|
203
232
|
def normalize_queues: (untyped) -> Hash[String, QueueConfig]
|
|
@@ -308,6 +337,7 @@ module River
|
|
|
308
337
|
@next_handle: Integer
|
|
309
338
|
@wake: untyped
|
|
310
339
|
def initialize: (Array[PeriodicJob], wake: untyped, ?enabled: bool) -> void
|
|
340
|
+
def __due_with_times: (Time) ?{ (PeriodicJob, StandardError) -> void } -> Array[[PeriodicJob, Time]]
|
|
311
341
|
def add: (PeriodicJob) -> Integer
|
|
312
342
|
def add_many: (Array[PeriodicJob]) -> Array[Integer]
|
|
313
343
|
def clear: () -> self
|
|
@@ -334,13 +364,22 @@ module River
|
|
|
334
364
|
@condition: ConditionVariable
|
|
335
365
|
@config: Config
|
|
336
366
|
@driver: _Driver
|
|
367
|
+
@fetching_queues: Hash[String, Array[Integer]]
|
|
368
|
+
@leader: bool
|
|
369
|
+
@maintenance_condition: ConditionVariable
|
|
370
|
+
@maintenance_generation: Integer
|
|
337
371
|
@maintenance_thread: Thread?
|
|
338
372
|
@mutex: Mutex
|
|
339
|
-
@
|
|
373
|
+
@notification_thread: Thread?
|
|
374
|
+
@notifications_disabled: bool
|
|
340
375
|
@performing: bool?
|
|
376
|
+
@periodic_jobs: PeriodicJobBundle
|
|
341
377
|
@producer_threads: Hash[String, Thread]
|
|
342
378
|
@queue_configs: Hash[String, QueueConfig]
|
|
379
|
+
@queue_generations: Hash[String, Integer]
|
|
380
|
+
@queue_paused: Hash[String, bool]
|
|
343
381
|
@removed_queues: Hash[String, bool]
|
|
382
|
+
@resign_requested: bool
|
|
344
383
|
@running: Hash[Integer, untyped]
|
|
345
384
|
@started: bool
|
|
346
385
|
@stop_requested: bool
|
|
@@ -373,6 +412,7 @@ module River
|
|
|
373
412
|
def finish_failed: (JobRow, Job, Exception, JobTiming, ?cancelled: bool, ?worker: untyped) -> untyped
|
|
374
413
|
def finish_interrupted: (JobRow, Job, JobTiming) -> untyped
|
|
375
414
|
def finish_snoozed: (JobRow, Job, JobSnoozeError, JobTiming) -> untyped
|
|
415
|
+
def finish_transactional_completion: (Job, JobTiming) -> bool
|
|
376
416
|
def finish_work: (Integer) -> untyped
|
|
377
417
|
def invoke_plugins: (Symbol, *untyped) -> Array[untyped]
|
|
378
418
|
def invoke_worker: (untyped, Job) -> untyped
|
|
@@ -381,22 +421,30 @@ module River
|
|
|
381
421
|
def monotonic_now: () -> Float
|
|
382
422
|
def next_retry: (JobRow, Exception, Time, ?worker: untyped) -> Time
|
|
383
423
|
def next_snooze_count: (untyped) -> Integer
|
|
424
|
+
def notification_loop: (untyped) -> untyped
|
|
425
|
+
def notifications_stopping?: () -> bool
|
|
384
426
|
def retry_allowed?: (untyped, Job, Exception) -> untyped
|
|
385
427
|
def perform_work: (untyped, Job) -> untyped
|
|
386
428
|
def periodic_jobs_changed: () -> untyped
|
|
387
429
|
def producer_loop: (String, QueueConfig) -> untyped
|
|
388
430
|
def publish: (Symbol, JobRow, JobTiming) -> untyped
|
|
389
431
|
def queue_stopping?: (String) -> bool
|
|
432
|
+
def receive_notification: (untyped, untyped) -> untyped
|
|
390
433
|
def remove_subscription: (Subscription) -> Subscription?
|
|
391
434
|
def rescue_job?: (JobRow, Time) -> bool
|
|
392
435
|
def resolve_worker: (String) -> untyped
|
|
393
436
|
def run_periodic: (Time) -> untyped
|
|
394
437
|
def running_count: (String) -> Integer
|
|
395
438
|
def start_maintenance: () -> untyped
|
|
439
|
+
def start_notifications: () -> untyped
|
|
396
440
|
def start_producer: (String, QueueConfig) -> untyped
|
|
397
441
|
def stopping?: () -> bool
|
|
398
442
|
def wait: (Float | Integer) -> untyped
|
|
443
|
+
def wait_for_maintenance: (Float | Integer, Integer) -> untyped
|
|
444
|
+
def wait_for_queue: (String, Float | Integer, Integer) -> untyped
|
|
399
445
|
def wait_for_running_jobs: (String, Float | Integer) -> untyped
|
|
446
|
+
def wake_maintenance: () -> untyped
|
|
447
|
+
def wake_queue: (String) -> untyped
|
|
400
448
|
def worker_timeout: (untyped, Job) -> Float?
|
|
401
449
|
end
|
|
402
450
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: riverqueue
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.14.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Blake Gentry
|
|
@@ -91,7 +91,7 @@ dependencies:
|
|
|
91
91
|
- !ruby/object:Gem::Version
|
|
92
92
|
version: '1000'
|
|
93
93
|
description: Insert and work River jobs in Ruby using the same schema and state machine
|
|
94
|
-
as River
|
|
94
|
+
as other River clients. Use with riverqueue-activerecord or riverqueue-sequel.
|
|
95
95
|
email: brandur@brandur.org
|
|
96
96
|
executables:
|
|
97
97
|
- river
|
|
@@ -113,6 +113,7 @@ files:
|
|
|
113
113
|
- lib/config.rb
|
|
114
114
|
- lib/driver.rb
|
|
115
115
|
- lib/driver/job_row_decoder.rb
|
|
116
|
+
- lib/driver/notification_listener.rb
|
|
116
117
|
- lib/driver/postgres_capabilities.rb
|
|
117
118
|
- lib/driver/runtime.rb
|
|
118
119
|
- lib/errors.rb
|
|
@@ -205,5 +206,5 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
205
206
|
requirements: []
|
|
206
207
|
rubygems_version: 4.0.9
|
|
207
208
|
specification_version: 4
|
|
208
|
-
summary: A fast, reliable job queue for Ruby backed by
|
|
209
|
+
summary: A fast, reliable job queue for Ruby backed by Postgres or SQLite.
|
|
209
210
|
test_files: []
|