riverqueue 0.11.0 → 0.12.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 +132 -0
- data/LICENSE +374 -0
- data/docs/README.md +765 -0
- data/docs/migrations.md +121 -0
- data/docs/testing.md +173 -0
- data/docs/workers.md +126 -0
- data/exe/river +7 -0
- data/lib/cli.rb +55 -0
- data/lib/client.rb +314 -54
- data/lib/client_runtime.rb +612 -0
- data/lib/config.rb +154 -0
- data/lib/driver/job_row_decoder.rb +85 -0
- data/lib/driver/postgres_capabilities.rb +41 -0
- data/lib/driver/runtime.rb +661 -0
- data/lib/driver.rb +13 -6
- data/lib/errors.rb +83 -0
- data/lib/event.rb +78 -0
- data/lib/insert_opts.rb +40 -11
- data/lib/job.rb +28 -13
- data/lib/job_persisted_logging/plugin.rb +108 -0
- data/lib/migration_cli.rb +90 -0
- data/lib/migrator.rb +189 -0
- data/lib/params.rb +96 -0
- data/lib/periodic_cron.rb +24 -0
- data/lib/periodic_job.rb +135 -0
- data/lib/resumable.rb +148 -0
- data/lib/riverqueue/testing/minitest.rb +18 -0
- data/lib/riverqueue/testing/rspec.rb +109 -0
- data/lib/riverqueue/testing.rb +134 -0
- data/lib/riverqueue.rb +16 -0
- data/lib/unique_args.rb +97 -0
- data/lib/unique_bitmask.rb +14 -12
- data/lib/worker.rb +152 -0
- data/lib/worker_runner.rb +106 -0
- data/migration/LICENSE +374 -0
- data/migration/README.md +11 -0
- data/migration/manifest.json +38 -0
- data/migration/postgresql/main/001_create_river_migration.down.sql +1 -0
- data/migration/postgresql/main/001_create_river_migration.up.sql +8 -0
- data/migration/postgresql/main/002_initial_schema.down.sql +5 -0
- data/migration/postgresql/main/002_initial_schema.up.sql +96 -0
- data/migration/postgresql/main/003_river_job_tags_non_null.down.sql +3 -0
- data/migration/postgresql/main/003_river_job_tags_non_null.up.sql +3 -0
- data/migration/postgresql/main/004_pending_and_more.down.sql +42 -0
- data/migration/postgresql/main/004_pending_and_more.up.sql +45 -0
- data/migration/postgresql/main/005_migration_unique_client.down.sql +57 -0
- data/migration/postgresql/main/005_migration_unique_client.up.sql +79 -0
- data/migration/postgresql/main/006_bulk_unique.down.sql +16 -0
- data/migration/postgresql/main/006_bulk_unique.up.sql +40 -0
- data/migration/postgresql/main/007_notification_outbox_sqlite_jsonb_and_sql_cleanup.down.sql +56 -0
- data/migration/postgresql/main/007_notification_outbox_sqlite_jsonb_and_sql_cleanup.up.sql +44 -0
- data/migration/postgresql/main/008_job_id_autoincrement.down.sql +3 -0
- data/migration/postgresql/main/008_job_id_autoincrement.up.sql +3 -0
- data/migration/sqlite/main/001_create_river_migration.down.sql +1 -0
- data/migration/sqlite/main/001_create_river_migration.up.sql +8 -0
- data/migration/sqlite/main/002_initial_schema.down.sql +8 -0
- data/migration/sqlite/main/002_initial_schema.up.sql +19 -0
- data/migration/sqlite/main/003_river_job_tags_non_null.down.sql +6 -0
- data/migration/sqlite/main/003_river_job_tags_non_null.up.sql +6 -0
- data/migration/sqlite/main/004_pending_and_more.down.sql +26 -0
- data/migration/sqlite/main/004_pending_and_more.up.sql +33 -0
- data/migration/sqlite/main/005_migration_unique_client.down.sql +37 -0
- data/migration/sqlite/main/005_migration_unique_client.up.sql +64 -0
- data/migration/sqlite/main/006_bulk_unique.down.sql +7 -0
- data/migration/sqlite/main/006_bulk_unique.up.sql +63 -0
- data/migration/sqlite/main/007_notification_outbox_sqlite_jsonb_and_sql_cleanup.down.sql +255 -0
- data/migration/sqlite/main/007_notification_outbox_sqlite_jsonb_and_sql_cleanup.up.sql +261 -0
- data/migration/sqlite/main/008_job_id_autoincrement.down.sql +121 -0
- data/migration/sqlite/main/008_job_id_autoincrement.up.sql +123 -0
- data/sig/client.rbs +95 -0
- data/sig/driver.rbs +170 -0
- data/sig/insert_opts.rbs +25 -0
- data/sig/job.rbs +72 -0
- data/sig/job_persisted_logging/plugin.rbs +29 -0
- data/sig/migrator.rbs +44 -0
- data/sig/riverqueue.rbs +2 -0
- data/sig/runtime.rbs +382 -0
- data/sig/testing.rbs +95 -0
- data/sig/unique_args.rbs +8 -0
- data/sig/unique_bitmask.rbs +8 -0
- data/sig/worker_runner.rbs +22 -0
- metadata +165 -10
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
--
|
|
2
|
+
-- SQL cleanup rollback.
|
|
3
|
+
--
|
|
4
|
+
|
|
5
|
+
--
|
|
6
|
+
-- Add back unused tables `river_client` and `river_client_queue`.
|
|
7
|
+
--
|
|
8
|
+
|
|
9
|
+
CREATE TABLE /* TEMPLATE: schema */river_client (
|
|
10
|
+
id text PRIMARY KEY NOT NULL,
|
|
11
|
+
created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
12
|
+
metadata blob NOT NULL DEFAULT (jsonb('{}')),
|
|
13
|
+
paused_at timestamp,
|
|
14
|
+
updated_at timestamp NOT NULL,
|
|
15
|
+
CONSTRAINT name_length CHECK (length(id) > 0 AND length(id) < 128)
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
CREATE TABLE /* TEMPLATE: schema */river_client_queue (
|
|
19
|
+
river_client_id text NOT NULL REFERENCES river_client (id) ON DELETE CASCADE,
|
|
20
|
+
name text NOT NULL,
|
|
21
|
+
created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
22
|
+
max_workers integer NOT NULL DEFAULT 0,
|
|
23
|
+
metadata blob NOT NULL DEFAULT (jsonb('{}')),
|
|
24
|
+
num_jobs_completed integer NOT NULL DEFAULT 0,
|
|
25
|
+
num_jobs_running integer NOT NULL DEFAULT 0,
|
|
26
|
+
updated_at timestamp NOT NULL,
|
|
27
|
+
PRIMARY KEY (river_client_id, name),
|
|
28
|
+
CONSTRAINT name_length CHECK (length(name) > 0 AND length(name) < 128),
|
|
29
|
+
CONSTRAINT num_jobs_completed_zero_or_positive CHECK (num_jobs_completed >= 0),
|
|
30
|
+
CONSTRAINT num_jobs_running_zero_or_positive CHECK (num_jobs_running >= 0)
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
--
|
|
34
|
+
-- SQLite JSONB conversion rollback.
|
|
35
|
+
--
|
|
36
|
+
-- Convert JSONB binary columns back to JSON text format and restore json()
|
|
37
|
+
-- defaults. The `river_job` rebuild also reverts the addition of `DEFAULT 25`
|
|
38
|
+
-- to `river_job.max_attempts`.
|
|
39
|
+
--
|
|
40
|
+
-- SQLite doesn't allow `ALTER TABLE ADD COLUMN` with non-constant defaults like
|
|
41
|
+
-- `json('{}')`, so rebuild each affected table instead.
|
|
42
|
+
--
|
|
43
|
+
|
|
44
|
+
--
|
|
45
|
+
-- river_job
|
|
46
|
+
--
|
|
47
|
+
|
|
48
|
+
DROP INDEX /* TEMPLATE: schema */river_job_kind;
|
|
49
|
+
DROP INDEX /* TEMPLATE: schema */river_job_state_and_finalized_at_index;
|
|
50
|
+
DROP INDEX /* TEMPLATE: schema */river_job_prioritized_fetching_index;
|
|
51
|
+
DROP INDEX /* TEMPLATE: schema */river_job_unique_idx;
|
|
52
|
+
|
|
53
|
+
ALTER TABLE /* TEMPLATE: schema */river_job RENAME TO river_job_old;
|
|
54
|
+
|
|
55
|
+
CREATE TABLE /* TEMPLATE: schema */river_job (
|
|
56
|
+
id integer PRIMARY KEY, -- SQLite aliases this to ROWID, which may reuse deleted IDs.
|
|
57
|
+
args blob NOT NULL DEFAULT '{}',
|
|
58
|
+
attempt integer NOT NULL DEFAULT 0,
|
|
59
|
+
attempted_at timestamp,
|
|
60
|
+
attempted_by blob, -- json
|
|
61
|
+
created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
62
|
+
errors blob, -- json
|
|
63
|
+
finalized_at timestamp,
|
|
64
|
+
kind text NOT NULL,
|
|
65
|
+
max_attempts integer NOT NULL,
|
|
66
|
+
metadata blob NOT NULL DEFAULT (json('{}')),
|
|
67
|
+
priority integer NOT NULL DEFAULT 1,
|
|
68
|
+
queue text NOT NULL DEFAULT 'default',
|
|
69
|
+
state text NOT NULL DEFAULT 'available',
|
|
70
|
+
scheduled_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
71
|
+
tags blob NOT NULL DEFAULT (json('[]')),
|
|
72
|
+
unique_key blob,
|
|
73
|
+
unique_states integer,
|
|
74
|
+
CONSTRAINT finalized_or_finalized_at_null CHECK (
|
|
75
|
+
(finalized_at IS NULL AND state NOT IN ('cancelled', 'completed', 'discarded')) OR
|
|
76
|
+
(finalized_at IS NOT NULL AND state IN ('cancelled', 'completed', 'discarded'))
|
|
77
|
+
),
|
|
78
|
+
CONSTRAINT priority_in_range CHECK (priority >= 1 AND priority <= 4),
|
|
79
|
+
CONSTRAINT queue_length CHECK (length(queue) > 0 AND length(queue) < 128),
|
|
80
|
+
CONSTRAINT kind_length CHECK (length(kind) > 0 AND length(kind) < 128),
|
|
81
|
+
CONSTRAINT state_valid CHECK (state IN ('available', 'cancelled', 'completed', 'discarded', 'pending', 'retryable', 'running', 'scheduled'))
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
INSERT INTO /* TEMPLATE: schema */river_job (
|
|
85
|
+
id,
|
|
86
|
+
args,
|
|
87
|
+
attempt,
|
|
88
|
+
attempted_at,
|
|
89
|
+
attempted_by,
|
|
90
|
+
created_at,
|
|
91
|
+
errors,
|
|
92
|
+
finalized_at,
|
|
93
|
+
kind,
|
|
94
|
+
max_attempts,
|
|
95
|
+
metadata,
|
|
96
|
+
priority,
|
|
97
|
+
queue,
|
|
98
|
+
state,
|
|
99
|
+
scheduled_at,
|
|
100
|
+
tags,
|
|
101
|
+
unique_key,
|
|
102
|
+
unique_states
|
|
103
|
+
)
|
|
104
|
+
SELECT
|
|
105
|
+
id,
|
|
106
|
+
json(args),
|
|
107
|
+
attempt,
|
|
108
|
+
attempted_at,
|
|
109
|
+
CASE WHEN attempted_by IS NULL THEN NULL ELSE json(attempted_by) END,
|
|
110
|
+
created_at,
|
|
111
|
+
CASE WHEN errors IS NULL THEN NULL ELSE json(errors) END,
|
|
112
|
+
finalized_at,
|
|
113
|
+
kind,
|
|
114
|
+
max_attempts,
|
|
115
|
+
json(metadata),
|
|
116
|
+
priority,
|
|
117
|
+
queue,
|
|
118
|
+
state,
|
|
119
|
+
scheduled_at,
|
|
120
|
+
json(tags),
|
|
121
|
+
unique_key,
|
|
122
|
+
unique_states
|
|
123
|
+
FROM /* TEMPLATE: schema */river_job_old;
|
|
124
|
+
|
|
125
|
+
DROP TABLE /* TEMPLATE: schema */river_job_old;
|
|
126
|
+
|
|
127
|
+
CREATE INDEX /* TEMPLATE: schema */river_job_kind ON river_job (kind);
|
|
128
|
+
CREATE INDEX /* TEMPLATE: schema */river_job_state_and_finalized_at_index ON river_job (state, finalized_at) WHERE finalized_at IS NOT NULL;
|
|
129
|
+
CREATE INDEX /* TEMPLATE: schema */river_job_prioritized_fetching_index ON river_job (state, queue, priority, scheduled_at, id);
|
|
130
|
+
CREATE UNIQUE INDEX /* TEMPLATE: schema */river_job_unique_idx ON river_job (unique_key)
|
|
131
|
+
WHERE unique_key IS NOT NULL
|
|
132
|
+
AND unique_states IS NOT NULL
|
|
133
|
+
AND CASE state
|
|
134
|
+
WHEN 'available' THEN unique_states & (1 << 0)
|
|
135
|
+
WHEN 'cancelled' THEN unique_states & (1 << 1)
|
|
136
|
+
WHEN 'completed' THEN unique_states & (1 << 2)
|
|
137
|
+
WHEN 'discarded' THEN unique_states & (1 << 3)
|
|
138
|
+
WHEN 'pending' THEN unique_states & (1 << 4)
|
|
139
|
+
WHEN 'retryable' THEN unique_states & (1 << 5)
|
|
140
|
+
WHEN 'running' THEN unique_states & (1 << 6)
|
|
141
|
+
WHEN 'scheduled' THEN unique_states & (1 << 7)
|
|
142
|
+
ELSE 0
|
|
143
|
+
END >= 1;
|
|
144
|
+
|
|
145
|
+
--
|
|
146
|
+
-- river_queue
|
|
147
|
+
--
|
|
148
|
+
|
|
149
|
+
ALTER TABLE /* TEMPLATE: schema */river_queue RENAME TO river_queue_old;
|
|
150
|
+
|
|
151
|
+
CREATE TABLE /* TEMPLATE: schema */river_queue (
|
|
152
|
+
name text PRIMARY KEY NOT NULL,
|
|
153
|
+
created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
154
|
+
metadata blob NOT NULL DEFAULT (json('{}')),
|
|
155
|
+
paused_at timestamp,
|
|
156
|
+
updated_at timestamp NOT NULL
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
INSERT INTO /* TEMPLATE: schema */river_queue (
|
|
160
|
+
name,
|
|
161
|
+
created_at,
|
|
162
|
+
metadata,
|
|
163
|
+
paused_at,
|
|
164
|
+
updated_at
|
|
165
|
+
)
|
|
166
|
+
SELECT
|
|
167
|
+
name,
|
|
168
|
+
created_at,
|
|
169
|
+
json(metadata),
|
|
170
|
+
paused_at,
|
|
171
|
+
updated_at
|
|
172
|
+
FROM /* TEMPLATE: schema */river_queue_old;
|
|
173
|
+
|
|
174
|
+
DROP TABLE /* TEMPLATE: schema */river_queue_old;
|
|
175
|
+
|
|
176
|
+
--
|
|
177
|
+
-- river_client
|
|
178
|
+
--
|
|
179
|
+
|
|
180
|
+
ALTER TABLE /* TEMPLATE: schema */river_client RENAME TO river_client_old;
|
|
181
|
+
|
|
182
|
+
CREATE TABLE /* TEMPLATE: schema */river_client (
|
|
183
|
+
id text PRIMARY KEY NOT NULL,
|
|
184
|
+
created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
185
|
+
metadata blob NOT NULL DEFAULT (json('{}')),
|
|
186
|
+
paused_at timestamp,
|
|
187
|
+
updated_at timestamp NOT NULL,
|
|
188
|
+
CONSTRAINT name_length CHECK (length(id) > 0 AND length(id) < 128)
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
INSERT INTO /* TEMPLATE: schema */river_client (
|
|
192
|
+
id,
|
|
193
|
+
created_at,
|
|
194
|
+
metadata,
|
|
195
|
+
paused_at,
|
|
196
|
+
updated_at
|
|
197
|
+
)
|
|
198
|
+
SELECT
|
|
199
|
+
id,
|
|
200
|
+
created_at,
|
|
201
|
+
json(metadata),
|
|
202
|
+
paused_at,
|
|
203
|
+
updated_at
|
|
204
|
+
FROM /* TEMPLATE: schema */river_client_old;
|
|
205
|
+
|
|
206
|
+
--
|
|
207
|
+
-- river_client_queue
|
|
208
|
+
--
|
|
209
|
+
|
|
210
|
+
ALTER TABLE /* TEMPLATE: schema */river_client_queue RENAME TO river_client_queue_old;
|
|
211
|
+
|
|
212
|
+
CREATE TABLE /* TEMPLATE: schema */river_client_queue (
|
|
213
|
+
river_client_id text NOT NULL REFERENCES river_client (id) ON DELETE CASCADE,
|
|
214
|
+
name text NOT NULL,
|
|
215
|
+
created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
216
|
+
max_workers integer NOT NULL DEFAULT 0,
|
|
217
|
+
metadata blob NOT NULL DEFAULT (json('{}')),
|
|
218
|
+
num_jobs_completed integer NOT NULL DEFAULT 0,
|
|
219
|
+
num_jobs_running integer NOT NULL DEFAULT 0,
|
|
220
|
+
updated_at timestamp NOT NULL,
|
|
221
|
+
PRIMARY KEY (river_client_id, name),
|
|
222
|
+
CONSTRAINT name_length CHECK (length(name) > 0 AND length(name) < 128),
|
|
223
|
+
CONSTRAINT num_jobs_completed_zero_or_positive CHECK (num_jobs_completed >= 0),
|
|
224
|
+
CONSTRAINT num_jobs_running_zero_or_positive CHECK (num_jobs_running >= 0)
|
|
225
|
+
);
|
|
226
|
+
|
|
227
|
+
INSERT INTO /* TEMPLATE: schema */river_client_queue (
|
|
228
|
+
river_client_id,
|
|
229
|
+
name,
|
|
230
|
+
created_at,
|
|
231
|
+
max_workers,
|
|
232
|
+
metadata,
|
|
233
|
+
num_jobs_completed,
|
|
234
|
+
num_jobs_running,
|
|
235
|
+
updated_at
|
|
236
|
+
)
|
|
237
|
+
SELECT
|
|
238
|
+
river_client_id,
|
|
239
|
+
name,
|
|
240
|
+
created_at,
|
|
241
|
+
max_workers,
|
|
242
|
+
json(metadata),
|
|
243
|
+
num_jobs_completed,
|
|
244
|
+
num_jobs_running,
|
|
245
|
+
updated_at
|
|
246
|
+
FROM /* TEMPLATE: schema */river_client_queue_old;
|
|
247
|
+
|
|
248
|
+
DROP TABLE /* TEMPLATE: schema */river_client_queue_old;
|
|
249
|
+
DROP TABLE /* TEMPLATE: schema */river_client_old;
|
|
250
|
+
|
|
251
|
+
--
|
|
252
|
+
-- Notification outbox rollback.
|
|
253
|
+
--
|
|
254
|
+
|
|
255
|
+
DROP TABLE /* TEMPLATE: schema */river_notification;
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
--
|
|
2
|
+
-- Notification outbox.
|
|
3
|
+
--
|
|
4
|
+
|
|
5
|
+
CREATE TABLE /* TEMPLATE: schema */river_notification (
|
|
6
|
+
id integer PRIMARY KEY AUTOINCREMENT,
|
|
7
|
+
created_at timestamp NOT NULL DEFAULT (datetime('now', 'subsec')),
|
|
8
|
+
payload text NOT NULL,
|
|
9
|
+
topic text NOT NULL,
|
|
10
|
+
CONSTRAINT topic_length CHECK (length(topic) > 0 AND length(topic) < 128)
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
CREATE INDEX /* TEMPLATE: schema */river_notification_created_at_idx ON river_notification (created_at);
|
|
14
|
+
CREATE INDEX /* TEMPLATE: schema */river_notification_topic_id_idx ON river_notification (topic, id);
|
|
15
|
+
|
|
16
|
+
--
|
|
17
|
+
-- SQLite JSONB conversion.
|
|
18
|
+
--
|
|
19
|
+
-- Convert JSON text columns to JSONB binary format for more efficient storage
|
|
20
|
+
-- and processing, and update column defaults from json() to jsonb().
|
|
21
|
+
--
|
|
22
|
+
-- SQLite doesn't allow `ALTER TABLE ADD COLUMN` with non-constant defaults like
|
|
23
|
+
-- `jsonb('{}')`, so rebuild each affected table instead.
|
|
24
|
+
--
|
|
25
|
+
|
|
26
|
+
--
|
|
27
|
+
-- river_job
|
|
28
|
+
--
|
|
29
|
+
|
|
30
|
+
DROP INDEX /* TEMPLATE: schema */river_job_kind;
|
|
31
|
+
DROP INDEX /* TEMPLATE: schema */river_job_state_and_finalized_at_index;
|
|
32
|
+
DROP INDEX /* TEMPLATE: schema */river_job_prioritized_fetching_index;
|
|
33
|
+
DROP INDEX /* TEMPLATE: schema */river_job_unique_idx;
|
|
34
|
+
|
|
35
|
+
ALTER TABLE /* TEMPLATE: schema */river_job RENAME TO river_job_old;
|
|
36
|
+
|
|
37
|
+
CREATE TABLE /* TEMPLATE: schema */river_job (
|
|
38
|
+
id integer PRIMARY KEY, -- SQLite aliases this to ROWID, which may reuse deleted IDs.
|
|
39
|
+
args blob NOT NULL DEFAULT (jsonb('{}')),
|
|
40
|
+
attempt integer NOT NULL DEFAULT 0,
|
|
41
|
+
attempted_at timestamp,
|
|
42
|
+
attempted_by blob, -- json
|
|
43
|
+
created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
44
|
+
errors blob, -- json
|
|
45
|
+
finalized_at timestamp,
|
|
46
|
+
kind text NOT NULL,
|
|
47
|
+
max_attempts integer NOT NULL,
|
|
48
|
+
metadata blob NOT NULL DEFAULT (jsonb('{}')),
|
|
49
|
+
priority integer NOT NULL DEFAULT 1,
|
|
50
|
+
queue text NOT NULL DEFAULT 'default',
|
|
51
|
+
state text NOT NULL DEFAULT 'available',
|
|
52
|
+
scheduled_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
53
|
+
tags blob NOT NULL DEFAULT (jsonb('[]')),
|
|
54
|
+
unique_key blob,
|
|
55
|
+
unique_states integer,
|
|
56
|
+
CONSTRAINT finalized_or_finalized_at_null CHECK (
|
|
57
|
+
(finalized_at IS NULL AND state NOT IN ('cancelled', 'completed', 'discarded')) OR
|
|
58
|
+
(finalized_at IS NOT NULL AND state IN ('cancelled', 'completed', 'discarded'))
|
|
59
|
+
),
|
|
60
|
+
CONSTRAINT priority_in_range CHECK (priority >= 1 AND priority <= 4),
|
|
61
|
+
CONSTRAINT queue_length CHECK (length(queue) > 0 AND length(queue) < 128),
|
|
62
|
+
CONSTRAINT kind_length CHECK (length(kind) > 0 AND length(kind) < 128),
|
|
63
|
+
CONSTRAINT state_valid CHECK (state IN ('available', 'cancelled', 'completed', 'discarded', 'pending', 'retryable', 'running', 'scheduled'))
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
INSERT INTO /* TEMPLATE: schema */river_job (
|
|
67
|
+
id,
|
|
68
|
+
args,
|
|
69
|
+
attempt,
|
|
70
|
+
attempted_at,
|
|
71
|
+
attempted_by,
|
|
72
|
+
created_at,
|
|
73
|
+
errors,
|
|
74
|
+
finalized_at,
|
|
75
|
+
kind,
|
|
76
|
+
max_attempts,
|
|
77
|
+
metadata,
|
|
78
|
+
priority,
|
|
79
|
+
queue,
|
|
80
|
+
state,
|
|
81
|
+
scheduled_at,
|
|
82
|
+
tags,
|
|
83
|
+
unique_key,
|
|
84
|
+
unique_states
|
|
85
|
+
)
|
|
86
|
+
SELECT
|
|
87
|
+
id,
|
|
88
|
+
jsonb(args),
|
|
89
|
+
attempt,
|
|
90
|
+
attempted_at,
|
|
91
|
+
CASE WHEN attempted_by IS NULL THEN NULL ELSE jsonb(attempted_by) END,
|
|
92
|
+
created_at,
|
|
93
|
+
CASE WHEN errors IS NULL THEN NULL ELSE jsonb(errors) END,
|
|
94
|
+
finalized_at,
|
|
95
|
+
kind,
|
|
96
|
+
max_attempts,
|
|
97
|
+
jsonb(metadata),
|
|
98
|
+
priority,
|
|
99
|
+
queue,
|
|
100
|
+
state,
|
|
101
|
+
scheduled_at,
|
|
102
|
+
jsonb(tags),
|
|
103
|
+
unique_key,
|
|
104
|
+
unique_states
|
|
105
|
+
FROM /* TEMPLATE: schema */river_job_old;
|
|
106
|
+
|
|
107
|
+
DROP TABLE /* TEMPLATE: schema */river_job_old;
|
|
108
|
+
|
|
109
|
+
CREATE INDEX /* TEMPLATE: schema */river_job_kind ON river_job (kind);
|
|
110
|
+
CREATE INDEX /* TEMPLATE: schema */river_job_state_and_finalized_at_index ON river_job (state, finalized_at) WHERE finalized_at IS NOT NULL;
|
|
111
|
+
CREATE INDEX /* TEMPLATE: schema */river_job_prioritized_fetching_index ON river_job (state, queue, priority, scheduled_at, id);
|
|
112
|
+
CREATE UNIQUE INDEX /* TEMPLATE: schema */river_job_unique_idx ON river_job (unique_key)
|
|
113
|
+
WHERE unique_key IS NOT NULL
|
|
114
|
+
AND unique_states IS NOT NULL
|
|
115
|
+
AND CASE state
|
|
116
|
+
WHEN 'available' THEN unique_states & (1 << 0)
|
|
117
|
+
WHEN 'cancelled' THEN unique_states & (1 << 1)
|
|
118
|
+
WHEN 'completed' THEN unique_states & (1 << 2)
|
|
119
|
+
WHEN 'discarded' THEN unique_states & (1 << 3)
|
|
120
|
+
WHEN 'pending' THEN unique_states & (1 << 4)
|
|
121
|
+
WHEN 'retryable' THEN unique_states & (1 << 5)
|
|
122
|
+
WHEN 'running' THEN unique_states & (1 << 6)
|
|
123
|
+
WHEN 'scheduled' THEN unique_states & (1 << 7)
|
|
124
|
+
ELSE 0
|
|
125
|
+
END >= 1;
|
|
126
|
+
|
|
127
|
+
--
|
|
128
|
+
-- river_queue
|
|
129
|
+
--
|
|
130
|
+
|
|
131
|
+
ALTER TABLE /* TEMPLATE: schema */river_queue RENAME TO river_queue_old;
|
|
132
|
+
|
|
133
|
+
CREATE TABLE /* TEMPLATE: schema */river_queue (
|
|
134
|
+
name text PRIMARY KEY NOT NULL,
|
|
135
|
+
created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
136
|
+
metadata blob NOT NULL DEFAULT (jsonb('{}')),
|
|
137
|
+
paused_at timestamp,
|
|
138
|
+
updated_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
INSERT INTO /* TEMPLATE: schema */river_queue (
|
|
142
|
+
name,
|
|
143
|
+
created_at,
|
|
144
|
+
metadata,
|
|
145
|
+
paused_at,
|
|
146
|
+
updated_at
|
|
147
|
+
)
|
|
148
|
+
SELECT
|
|
149
|
+
name,
|
|
150
|
+
created_at,
|
|
151
|
+
jsonb(metadata),
|
|
152
|
+
paused_at,
|
|
153
|
+
updated_at
|
|
154
|
+
FROM /* TEMPLATE: schema */river_queue_old;
|
|
155
|
+
|
|
156
|
+
DROP TABLE /* TEMPLATE: schema */river_queue_old;
|
|
157
|
+
|
|
158
|
+
--
|
|
159
|
+
-- river_client
|
|
160
|
+
--
|
|
161
|
+
|
|
162
|
+
ALTER TABLE /* TEMPLATE: schema */river_client RENAME TO river_client_old;
|
|
163
|
+
|
|
164
|
+
CREATE TABLE /* TEMPLATE: schema */river_client (
|
|
165
|
+
id text PRIMARY KEY NOT NULL,
|
|
166
|
+
created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
167
|
+
metadata blob NOT NULL DEFAULT (jsonb('{}')),
|
|
168
|
+
paused_at timestamp,
|
|
169
|
+
updated_at timestamp NOT NULL,
|
|
170
|
+
CONSTRAINT name_length CHECK (length(id) > 0 AND length(id) < 128)
|
|
171
|
+
);
|
|
172
|
+
|
|
173
|
+
INSERT INTO /* TEMPLATE: schema */river_client (
|
|
174
|
+
id,
|
|
175
|
+
created_at,
|
|
176
|
+
metadata,
|
|
177
|
+
paused_at,
|
|
178
|
+
updated_at
|
|
179
|
+
)
|
|
180
|
+
SELECT
|
|
181
|
+
id,
|
|
182
|
+
created_at,
|
|
183
|
+
jsonb(metadata),
|
|
184
|
+
paused_at,
|
|
185
|
+
updated_at
|
|
186
|
+
FROM /* TEMPLATE: schema */river_client_old;
|
|
187
|
+
|
|
188
|
+
--
|
|
189
|
+
-- river_client_queue
|
|
190
|
+
--
|
|
191
|
+
|
|
192
|
+
ALTER TABLE /* TEMPLATE: schema */river_client_queue RENAME TO river_client_queue_old;
|
|
193
|
+
|
|
194
|
+
CREATE TABLE /* TEMPLATE: schema */river_client_queue (
|
|
195
|
+
river_client_id text NOT NULL REFERENCES river_client (id) ON DELETE CASCADE,
|
|
196
|
+
name text NOT NULL,
|
|
197
|
+
created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
198
|
+
max_workers integer NOT NULL DEFAULT 0,
|
|
199
|
+
metadata blob NOT NULL DEFAULT (jsonb('{}')),
|
|
200
|
+
num_jobs_completed integer NOT NULL DEFAULT 0,
|
|
201
|
+
num_jobs_running integer NOT NULL DEFAULT 0,
|
|
202
|
+
updated_at timestamp NOT NULL,
|
|
203
|
+
PRIMARY KEY (river_client_id, name),
|
|
204
|
+
CONSTRAINT name_length CHECK (length(name) > 0 AND length(name) < 128),
|
|
205
|
+
CONSTRAINT num_jobs_completed_zero_or_positive CHECK (num_jobs_completed >= 0),
|
|
206
|
+
CONSTRAINT num_jobs_running_zero_or_positive CHECK (num_jobs_running >= 0)
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
INSERT INTO /* TEMPLATE: schema */river_client_queue (
|
|
210
|
+
river_client_id,
|
|
211
|
+
name,
|
|
212
|
+
created_at,
|
|
213
|
+
max_workers,
|
|
214
|
+
metadata,
|
|
215
|
+
num_jobs_completed,
|
|
216
|
+
num_jobs_running,
|
|
217
|
+
updated_at
|
|
218
|
+
)
|
|
219
|
+
SELECT
|
|
220
|
+
river_client_id,
|
|
221
|
+
name,
|
|
222
|
+
created_at,
|
|
223
|
+
max_workers,
|
|
224
|
+
jsonb(metadata),
|
|
225
|
+
num_jobs_completed,
|
|
226
|
+
num_jobs_running,
|
|
227
|
+
updated_at
|
|
228
|
+
FROM /* TEMPLATE: schema */river_client_queue_old;
|
|
229
|
+
|
|
230
|
+
DROP TABLE /* TEMPLATE: schema */river_client_queue_old;
|
|
231
|
+
DROP TABLE /* TEMPLATE: schema */river_client_old;
|
|
232
|
+
|
|
233
|
+
--
|
|
234
|
+
-- SQL cleanup.
|
|
235
|
+
--
|
|
236
|
+
|
|
237
|
+
--
|
|
238
|
+
-- Drop unused tables `river_client` and `river_client_queue`.
|
|
239
|
+
--
|
|
240
|
+
|
|
241
|
+
DROP TABLE /* TEMPLATE: schema */river_client_queue;
|
|
242
|
+
DROP TABLE /* TEMPLATE: schema */river_client;
|
|
243
|
+
|
|
244
|
+
--
|
|
245
|
+
-- Adds `DEFAULT 25` to `river_job.max_attempts`.
|
|
246
|
+
--
|
|
247
|
+
|
|
248
|
+
-- This may look odd in that we're adding a brand new column, but it's because
|
|
249
|
+
-- SQLite doesn't support anything beyond the most trivial DDL.
|
|
250
|
+
|
|
251
|
+
ALTER TABLE /* TEMPLATE: schema */river_job
|
|
252
|
+
RENAME COLUMN max_attempts TO max_attempts_old;
|
|
253
|
+
|
|
254
|
+
ALTER TABLE /* TEMPLATE: schema */river_job
|
|
255
|
+
ADD COLUMN max_attempts integer NOT NULL DEFAULT 25;
|
|
256
|
+
|
|
257
|
+
UPDATE /* TEMPLATE: schema */river_job
|
|
258
|
+
SET max_attempts = max_attempts_old;
|
|
259
|
+
|
|
260
|
+
ALTER TABLE /* TEMPLATE: schema */river_job
|
|
261
|
+
DROP COLUMN max_attempts_old;
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
-- Rebuild river_job to restore SQLite's default ROWID allocation behavior.
|
|
2
|
+
|
|
3
|
+
-- Rebuilding river_job would discard schema installed by River Pro. Check
|
|
4
|
+
-- schema objects instead of migration records to also catch manually applied
|
|
5
|
+
-- Pro migrations and the legacy workflow migration line.
|
|
6
|
+
CREATE TEMP TABLE river_job_pro_schema_guard (
|
|
7
|
+
id integer NOT NULL
|
|
8
|
+
);
|
|
9
|
+
|
|
10
|
+
CREATE TEMP TRIGGER river_job_pro_schema_guard_enforce
|
|
11
|
+
BEFORE INSERT ON river_job_pro_schema_guard
|
|
12
|
+
WHEN EXISTS (
|
|
13
|
+
SELECT 1
|
|
14
|
+
FROM /* TEMPLATE: schema */sqlite_master
|
|
15
|
+
WHERE name IN ('river_job_sequence', 'river_job_workflow_scheduling', 'river_workflow')
|
|
16
|
+
)
|
|
17
|
+
BEGIN
|
|
18
|
+
SELECT RAISE(ABORT, 'River SQLite migration 008 cannot run while River Pro schema is installed');
|
|
19
|
+
END;
|
|
20
|
+
|
|
21
|
+
INSERT INTO river_job_pro_schema_guard (id) VALUES (1);
|
|
22
|
+
|
|
23
|
+
DROP TRIGGER river_job_pro_schema_guard_enforce;
|
|
24
|
+
DROP TABLE river_job_pro_schema_guard;
|
|
25
|
+
|
|
26
|
+
DROP INDEX /* TEMPLATE: schema */river_job_kind;
|
|
27
|
+
DROP INDEX /* TEMPLATE: schema */river_job_state_and_finalized_at_index;
|
|
28
|
+
DROP INDEX /* TEMPLATE: schema */river_job_prioritized_fetching_index;
|
|
29
|
+
DROP INDEX /* TEMPLATE: schema */river_job_unique_idx;
|
|
30
|
+
|
|
31
|
+
ALTER TABLE /* TEMPLATE: schema */river_job RENAME TO river_job_old;
|
|
32
|
+
|
|
33
|
+
CREATE TABLE /* TEMPLATE: schema */river_job (
|
|
34
|
+
id integer PRIMARY KEY,
|
|
35
|
+
args blob NOT NULL DEFAULT (jsonb('{}')),
|
|
36
|
+
attempt integer NOT NULL DEFAULT 0,
|
|
37
|
+
attempted_at timestamp,
|
|
38
|
+
attempted_by blob, -- json
|
|
39
|
+
created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
40
|
+
errors blob, -- json
|
|
41
|
+
finalized_at timestamp,
|
|
42
|
+
kind text NOT NULL,
|
|
43
|
+
max_attempts integer NOT NULL DEFAULT 25,
|
|
44
|
+
metadata blob NOT NULL DEFAULT (jsonb('{}')),
|
|
45
|
+
priority integer NOT NULL DEFAULT 1,
|
|
46
|
+
queue text NOT NULL DEFAULT 'default',
|
|
47
|
+
state text NOT NULL DEFAULT 'available',
|
|
48
|
+
scheduled_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
49
|
+
tags blob NOT NULL DEFAULT (jsonb('[]')),
|
|
50
|
+
unique_key blob,
|
|
51
|
+
unique_states integer,
|
|
52
|
+
CONSTRAINT finalized_or_finalized_at_null CHECK (
|
|
53
|
+
(finalized_at IS NULL AND state NOT IN ('cancelled', 'completed', 'discarded')) OR
|
|
54
|
+
(finalized_at IS NOT NULL AND state IN ('cancelled', 'completed', 'discarded'))
|
|
55
|
+
),
|
|
56
|
+
CONSTRAINT priority_in_range CHECK (priority >= 1 AND priority <= 4),
|
|
57
|
+
CONSTRAINT queue_length CHECK (length(queue) > 0 AND length(queue) < 128),
|
|
58
|
+
CONSTRAINT kind_length CHECK (length(kind) > 0 AND length(kind) < 128),
|
|
59
|
+
CONSTRAINT state_valid CHECK (state IN ('available', 'cancelled', 'completed', 'discarded', 'pending', 'retryable', 'running', 'scheduled'))
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
INSERT INTO /* TEMPLATE: schema */river_job (
|
|
63
|
+
id,
|
|
64
|
+
args,
|
|
65
|
+
attempt,
|
|
66
|
+
attempted_at,
|
|
67
|
+
attempted_by,
|
|
68
|
+
created_at,
|
|
69
|
+
errors,
|
|
70
|
+
finalized_at,
|
|
71
|
+
kind,
|
|
72
|
+
max_attempts,
|
|
73
|
+
metadata,
|
|
74
|
+
priority,
|
|
75
|
+
queue,
|
|
76
|
+
state,
|
|
77
|
+
scheduled_at,
|
|
78
|
+
tags,
|
|
79
|
+
unique_key,
|
|
80
|
+
unique_states
|
|
81
|
+
)
|
|
82
|
+
SELECT
|
|
83
|
+
id,
|
|
84
|
+
args,
|
|
85
|
+
attempt,
|
|
86
|
+
attempted_at,
|
|
87
|
+
attempted_by,
|
|
88
|
+
created_at,
|
|
89
|
+
errors,
|
|
90
|
+
finalized_at,
|
|
91
|
+
kind,
|
|
92
|
+
max_attempts,
|
|
93
|
+
metadata,
|
|
94
|
+
priority,
|
|
95
|
+
queue,
|
|
96
|
+
state,
|
|
97
|
+
scheduled_at,
|
|
98
|
+
tags,
|
|
99
|
+
unique_key,
|
|
100
|
+
unique_states
|
|
101
|
+
FROM /* TEMPLATE: schema */river_job_old;
|
|
102
|
+
|
|
103
|
+
DROP TABLE /* TEMPLATE: schema */river_job_old;
|
|
104
|
+
|
|
105
|
+
CREATE INDEX /* TEMPLATE: schema */river_job_kind ON river_job (kind);
|
|
106
|
+
CREATE INDEX /* TEMPLATE: schema */river_job_state_and_finalized_at_index ON river_job (state, finalized_at) WHERE finalized_at IS NOT NULL;
|
|
107
|
+
CREATE INDEX /* TEMPLATE: schema */river_job_prioritized_fetching_index ON river_job (state, queue, priority, scheduled_at, id);
|
|
108
|
+
CREATE UNIQUE INDEX /* TEMPLATE: schema */river_job_unique_idx ON river_job (unique_key)
|
|
109
|
+
WHERE unique_key IS NOT NULL
|
|
110
|
+
AND unique_states IS NOT NULL
|
|
111
|
+
AND CASE state
|
|
112
|
+
WHEN 'available' THEN unique_states & (1 << 0)
|
|
113
|
+
WHEN 'cancelled' THEN unique_states & (1 << 1)
|
|
114
|
+
WHEN 'completed' THEN unique_states & (1 << 2)
|
|
115
|
+
WHEN 'discarded' THEN unique_states & (1 << 3)
|
|
116
|
+
WHEN 'pending' THEN unique_states & (1 << 4)
|
|
117
|
+
WHEN 'retryable' THEN unique_states & (1 << 5)
|
|
118
|
+
WHEN 'running' THEN unique_states & (1 << 6)
|
|
119
|
+
WHEN 'scheduled' THEN unique_states & (1 << 7)
|
|
120
|
+
ELSE 0
|
|
121
|
+
END >= 1;
|