@pg-boss/dashboard 1.2.1 → 1.3.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.
- package/build/client/assets/MenuTrigger-BNvpjhsQ.js +1 -0
- package/build/client/assets/_index-DqpFaaQw.js +1 -0
- package/build/client/assets/{badge-DCQvSdiR.js → badge-CMnQO7Lq.js} +1 -1
- package/build/client/assets/{button-BxLcuaPM.js → button-9NpSS9Ow.js} +1 -1
- package/build/client/assets/check-7jwc5sb1.js +1 -0
- package/build/client/assets/{chevron-down-Byq-CYG9.js → chevron-down-BFFjfYD4.js} +1 -1
- package/build/client/assets/chevron-right-DGk5QFJF.js +1 -0
- package/build/client/assets/{createLucideIcon-DVP_i62f.js → createLucideIcon-C-LI4enx.js} +1 -1
- package/build/client/assets/db-link-BajQ1v8I.js +1 -0
- package/build/client/assets/dialog-D-oczDM2.js +1 -0
- package/build/client/assets/{entry.client-DL_oPh96.js → entry.client-CqyjuPDB.js} +3 -3
- package/build/client/assets/{error-card-B0ANyjh3.js → error-card-BH7i86fH.js} +1 -1
- package/build/client/assets/{filter-select--qLjbs9m.js → filter-select-Bn_oSiip.js} +1 -1
- package/build/client/assets/jobs-CAd_qqLH.js +1 -0
- package/build/client/assets/jsx-runtime-RQyiN6Nr.js +16 -0
- package/build/client/assets/manifest-27e8e133.js +1 -0
- package/build/client/assets/migrations-D5l0n4Jn.js +1 -0
- package/build/client/assets/{pagination-Bzx8wbXG.js → pagination-C-ohiBmY.js} +1 -1
- package/build/client/assets/queues._index-8YriSqbQ.js +1 -0
- package/build/client/assets/queues._name-Cb17IB2u.js +1 -0
- package/build/client/assets/{queues._name.jobs._jobId-BkG9y75k.js → queues._name.jobs._jobId-Bkv8POBj.js} +1 -1
- package/build/client/assets/{queues.create-CMqQVLup.js → queues.create-DsY0Sc19.js} +1 -1
- package/build/client/assets/{react-dom-QnGHOQwT.js → react-dom-D_m_Zgd3.js} +1 -1
- package/build/client/assets/root-B0MB8jZH.css +2 -0
- package/build/client/assets/root-qxoeL6W3.js +40 -0
- package/build/client/assets/{schedules-DPXQoaEE.js → schedules-iYfIJxOD.js} +1 -1
- package/build/client/assets/{schedules._name._key-B_luxy1w.js → schedules._name._key-CJVu73XY.js} +1 -1
- package/build/client/assets/{schedules.new-BQV7GWzs.js → schedules.new-Cq0Mxa7G.js} +1 -1
- package/build/client/assets/send-8X9ZisG-.js +1 -0
- package/build/client/assets/{stat-card-DLtQnscf.js → stat-card-dyg1wY5p.js} +1 -1
- package/build/client/assets/{table-DqqzSNik.js → table-Cz7ujmH_.js} +1 -1
- package/build/client/assets/useOpenInteractionType-BQ1arb0B.js +1 -0
- package/build/client/assets/{warnings-CHKaRfIW.js → warnings-C1R_RzIe.js} +1 -1
- package/build/client/assets/x-AhXI_F1j.js +1 -0
- package/build/server/index.js +2053 -1114
- package/package.json +11 -8
- package/build/client/assets/MenuTrigger-BhalG0aG.js +0 -1
- package/build/client/assets/_index-D1-nZ7Th.js +0 -1
- package/build/client/assets/check-Ch42cXMT.js +0 -1
- package/build/client/assets/chevron-right-CKAGD7DJ.js +0 -1
- package/build/client/assets/db-link-BWWnHM0k.js +0 -1
- package/build/client/assets/dialog-Bik519zD.js +0 -1
- package/build/client/assets/jobs-D0a6Lwq0.js +0 -1
- package/build/client/assets/jsx-runtime-BgbGXvsu.js +0 -16
- package/build/client/assets/manifest-ef81a0f9.js +0 -1
- package/build/client/assets/queues._index-D8903DTa.js +0 -1
- package/build/client/assets/queues._name-BVt_4pav.js +0 -1
- package/build/client/assets/root-C0MdPLOa.css +0 -2
- package/build/client/assets/root-Df70GAY3.js +0 -40
- package/build/client/assets/send-DJBsfnx_.js +0 -1
- package/build/client/assets/useOpenInteractionType-D3JsvupP.js +0 -1
- package/build/client/assets/x-BPKZwOn9.js +0 -1
package/build/server/index.js
CHANGED
|
@@ -347,6 +347,38 @@ var WARNING_TYPE_OPTIONS = [{
|
|
|
347
347
|
value: type,
|
|
348
348
|
label: WARNING_TYPE_LABELS[type]
|
|
349
349
|
}))];
|
|
350
|
+
var BAM_STATUSES = [
|
|
351
|
+
"pending",
|
|
352
|
+
"in_progress",
|
|
353
|
+
"completed",
|
|
354
|
+
"failed"
|
|
355
|
+
];
|
|
356
|
+
/**
|
|
357
|
+
* Validate a BAM status filter value
|
|
358
|
+
*/
|
|
359
|
+
function isValidBamStatus(value) {
|
|
360
|
+
if (value === null) return true;
|
|
361
|
+
return BAM_STATUSES.includes(value);
|
|
362
|
+
}
|
|
363
|
+
var BAM_STATUS_VARIANTS = {
|
|
364
|
+
pending: "gray",
|
|
365
|
+
in_progress: "primary",
|
|
366
|
+
completed: "success",
|
|
367
|
+
failed: "error"
|
|
368
|
+
};
|
|
369
|
+
var BAM_STATUS_LABELS = {
|
|
370
|
+
pending: "Pending",
|
|
371
|
+
in_progress: "In Progress",
|
|
372
|
+
completed: "Completed",
|
|
373
|
+
failed: "Failed"
|
|
374
|
+
};
|
|
375
|
+
var BAM_STATUS_OPTIONS = [{
|
|
376
|
+
value: null,
|
|
377
|
+
label: "All Statuses"
|
|
378
|
+
}, ...BAM_STATUSES.map((status) => ({
|
|
379
|
+
value: status,
|
|
380
|
+
label: BAM_STATUS_LABELS[status]
|
|
381
|
+
}))];
|
|
350
382
|
/**
|
|
351
383
|
* Format warning data for display
|
|
352
384
|
*/
|
|
@@ -840,6 +872,11 @@ var navigation = [
|
|
|
840
872
|
href: "/schedules",
|
|
841
873
|
icon: SchedulesIcon
|
|
842
874
|
},
|
|
875
|
+
{
|
|
876
|
+
name: "Migrations",
|
|
877
|
+
href: "/migrations",
|
|
878
|
+
icon: MigrationsIcon
|
|
879
|
+
},
|
|
843
880
|
{
|
|
844
881
|
name: "Warnings",
|
|
845
882
|
href: "/warnings",
|
|
@@ -916,6 +953,20 @@ function WarningIcon$1({ className }) {
|
|
|
916
953
|
})
|
|
917
954
|
});
|
|
918
955
|
}
|
|
956
|
+
function MigrationsIcon({ className }) {
|
|
957
|
+
return /* @__PURE__ */ jsx("svg", {
|
|
958
|
+
className,
|
|
959
|
+
fill: "none",
|
|
960
|
+
viewBox: "0 0 24 24",
|
|
961
|
+
strokeWidth: 1.5,
|
|
962
|
+
stroke: "currentColor",
|
|
963
|
+
children: /* @__PURE__ */ jsx("path", {
|
|
964
|
+
strokeLinecap: "round",
|
|
965
|
+
strokeLinejoin: "round",
|
|
966
|
+
d: "M7.5 21 3 16.5m0 0L7.5 12M3 16.5h13.5m0-13.5L21 7.5m0 0L16.5 12M21 7.5H7.5"
|
|
967
|
+
})
|
|
968
|
+
});
|
|
969
|
+
}
|
|
919
970
|
function DatabaseIcon({ className }) {
|
|
920
971
|
return /* @__PURE__ */ jsx("svg", {
|
|
921
972
|
className,
|
|
@@ -1208,11 +1259,11 @@ var dbContext = globalStore[TOKEN_KEY] ??= createContext();
|
|
|
1208
1259
|
//#endregion
|
|
1209
1260
|
//#region app/root.tsx
|
|
1210
1261
|
var root_exports = /* @__PURE__ */ __exportAll({
|
|
1211
|
-
ErrorBoundary: () => ErrorBoundary$
|
|
1262
|
+
ErrorBoundary: () => ErrorBoundary$12,
|
|
1212
1263
|
Layout: () => Layout,
|
|
1213
1264
|
default: () => root_default,
|
|
1214
1265
|
links: () => links,
|
|
1215
|
-
loader: () => loader$
|
|
1266
|
+
loader: () => loader$12,
|
|
1216
1267
|
meta: () => meta
|
|
1217
1268
|
});
|
|
1218
1269
|
function MainContent({ children }) {
|
|
@@ -1288,7 +1339,7 @@ var themeScript = `
|
|
|
1288
1339
|
link.href = 'data:image/svg+xml,' + encodeURIComponent(svg);
|
|
1289
1340
|
})();
|
|
1290
1341
|
`;
|
|
1291
|
-
async function loader$
|
|
1342
|
+
async function loader$12({ context }) {
|
|
1292
1343
|
const { databases, currentDb } = context.get(dbContext);
|
|
1293
1344
|
return {
|
|
1294
1345
|
databases,
|
|
@@ -1321,7 +1372,7 @@ function Layout({ children }) {
|
|
|
1321
1372
|
var root_default = UNSAFE_withComponentProps(function App() {
|
|
1322
1373
|
return /* @__PURE__ */ jsx(Outlet, {});
|
|
1323
1374
|
});
|
|
1324
|
-
var ErrorBoundary$
|
|
1375
|
+
var ErrorBoundary$12 = UNSAFE_withErrorBoundaryProps(function ErrorBoundary({ error }) {
|
|
1325
1376
|
let message = "Oops!";
|
|
1326
1377
|
let details = "An unexpected error occurred.";
|
|
1327
1378
|
let stack;
|
|
@@ -1517,7 +1568,8 @@ function createTableVersion(schema) {
|
|
|
1517
1568
|
CREATE TABLE ${schema}.version (
|
|
1518
1569
|
version int primary key,
|
|
1519
1570
|
cron_on timestamp with time zone,
|
|
1520
|
-
bam_on timestamp with time zone
|
|
1571
|
+
bam_on timestamp with time zone,
|
|
1572
|
+
flow_on timestamp with time zone
|
|
1521
1573
|
)
|
|
1522
1574
|
`;
|
|
1523
1575
|
}
|
|
@@ -1538,10 +1590,13 @@ function createTableQueue(schema) {
|
|
|
1538
1590
|
table_name text NOT NULL,
|
|
1539
1591
|
deferred_count int NOT NULL default 0,
|
|
1540
1592
|
queued_count int NOT NULL default 0,
|
|
1593
|
+
ready_count int NOT NULL default 0,
|
|
1541
1594
|
warning_queued int NOT NULL default 0,
|
|
1542
1595
|
active_count int NOT NULL default 0,
|
|
1596
|
+
failed_count int NOT NULL default 0,
|
|
1543
1597
|
total_count int NOT NULL default 0,
|
|
1544
1598
|
heartbeat_seconds int,
|
|
1599
|
+
notify bool NOT NULL DEFAULT false,
|
|
1545
1600
|
singletons_active text[],
|
|
1546
1601
|
monitor_on timestamp with time zone,
|
|
1547
1602
|
maintain_on timestamp with time zone,
|
|
@@ -1789,6 +1844,7 @@ function createTableJobCommon(schema) {
|
|
|
1789
1844
|
SELECT ${schema}.job_table_run($cmd$${createIndexJobThrottle(schema)}$cmd$, '${COMMON_JOB_TABLE}');
|
|
1790
1845
|
SELECT ${schema}.job_table_run($cmd$${createIndexJobFetch(schema)}$cmd$, '${COMMON_JOB_TABLE}');
|
|
1791
1846
|
SELECT ${schema}.job_table_run($cmd$${createIndexJobGroupConcurrency(schema)}$cmd$, '${COMMON_JOB_TABLE}');
|
|
1847
|
+
SELECT ${schema}.job_table_run($cmd$${createIndexJobBlocking(schema)}$cmd$, '${COMMON_JOB_TABLE}');
|
|
1792
1848
|
|
|
1793
1849
|
ALTER TABLE ${schema}.job ATTACH PARTITION ${schema}.${COMMON_JOB_TABLE} DEFAULT;
|
|
1794
1850
|
`;
|
|
@@ -1806,6 +1862,7 @@ function createTableJobIndexes(schema, noDeferrableConstraints = false, noCoveri
|
|
|
1806
1862
|
${createIndexJobThrottle(schema)};
|
|
1807
1863
|
${createIndexJobFetch(schema, noCoveringIndex)};
|
|
1808
1864
|
${createIndexJobGroupConcurrency(schema)};
|
|
1865
|
+
${createIndexJobBlocking(schema)};
|
|
1809
1866
|
`;
|
|
1810
1867
|
}
|
|
1811
1868
|
function createQueueFunction(schema, noPartitioning = false) {
|
|
@@ -1878,7 +1935,8 @@ function createQueueFunction(schema, noPartitioning = false) {
|
|
|
1878
1935
|
dead_letter,
|
|
1879
1936
|
partition,
|
|
1880
1937
|
table_name,
|
|
1881
|
-
heartbeat_seconds
|
|
1938
|
+
heartbeat_seconds,
|
|
1939
|
+
notify
|
|
1882
1940
|
)
|
|
1883
1941
|
VALUES (
|
|
1884
1942
|
queue_name,
|
|
@@ -1894,7 +1952,8 @@ function createQueueFunction(schema, noPartitioning = false) {
|
|
|
1894
1952
|
options->>'deadLetter',
|
|
1895
1953
|
COALESCE((options->>'partition')::bool, ${QUEUE_DEFAULTS.partition}),
|
|
1896
1954
|
tablename,
|
|
1897
|
-
(options->>'heartbeatSeconds')::int
|
|
1955
|
+
(options->>'heartbeatSeconds')::int,
|
|
1956
|
+
COALESCE((options->>'notify')::bool, false)
|
|
1898
1957
|
)
|
|
1899
1958
|
ON CONFLICT DO NOTHING
|
|
1900
1959
|
RETURNING created_on
|
|
@@ -1914,6 +1973,7 @@ function createQueueFunction(schema, noPartitioning = false) {
|
|
|
1914
1973
|
EXECUTE ${schema}.job_table_format($cmd$${createIndexJobFetch(schema)}$cmd$, tablename);
|
|
1915
1974
|
EXECUTE ${schema}.job_table_format($cmd$${createIndexJobThrottle(schema)}$cmd$, tablename);
|
|
1916
1975
|
EXECUTE ${schema}.job_table_format($cmd$${createIndexJobGroupConcurrency(schema)}$cmd$, tablename);
|
|
1976
|
+
EXECUTE ${schema}.job_table_format($cmd$${createIndexJobBlocking(schema)}$cmd$, tablename);
|
|
1917
1977
|
|
|
1918
1978
|
IF options->>'policy' = 'short' THEN
|
|
1919
1979
|
EXECUTE ${schema}.job_table_format($cmd$${createIndexJobPolicyShort(schema)}$cmd$, tablename);
|
|
@@ -1966,6 +2026,12 @@ function deleteQueueFunction(schema, noPartitioning = false) {
|
|
|
1966
2026
|
function createQueue$1(schema, name, options, noAdvisoryLocks) {
|
|
1967
2027
|
return locked(schema, `SELECT ${schema}.create_queue('${name}', '${JSON.stringify(options)}'::jsonb)`, "create-queue", noAdvisoryLocks);
|
|
1968
2028
|
}
|
|
2029
|
+
function notifyChannelSql(schema) {
|
|
2030
|
+
return `('pgboss_' || left(encode(sha224('${schema}'::bytea), 'hex'), 24))`;
|
|
2031
|
+
}
|
|
2032
|
+
function notifyQueue(schema, name) {
|
|
2033
|
+
return `SELECT pg_notify(${notifyChannelSql(schema)}, '${name}')`;
|
|
2034
|
+
}
|
|
1969
2035
|
function deleteQueue(schema, name, noAdvisoryLocks) {
|
|
1970
2036
|
return locked(schema, `SELECT ${schema}.delete_queue('${name}')`, "delete-queue", noAdvisoryLocks);
|
|
1971
2037
|
}
|
|
@@ -1991,7 +2057,7 @@ function createIndexJobThrottle(schema) {
|
|
|
1991
2057
|
return `CREATE UNIQUE INDEX job_i4 ON ${schema}.job (name, singleton_on, COALESCE(singleton_key, '')) WHERE state <> '${JOB_STATES.cancelled}' AND singleton_on IS NOT NULL`;
|
|
1992
2058
|
}
|
|
1993
2059
|
function createIndexJobFetch(schema, noCoveringIndex = false) {
|
|
1994
|
-
return `CREATE INDEX job_i5 ON ${schema}.job (name, start_after)
|
|
2060
|
+
return `CREATE INDEX job_i5 ON ${schema}.job (name, start_after) WHERE state < '${JOB_STATES.active}' AND NOT blocked`;
|
|
1995
2061
|
}
|
|
1996
2062
|
function createIndexJobPolicyExclusive(schema) {
|
|
1997
2063
|
return `CREATE UNIQUE INDEX job_i6 ON ${schema}.job (name, COALESCE(singleton_key, '')) WHERE state <= '${JOB_STATES.active}' AND policy = '${QUEUE_POLICIES.exclusive}'`;
|
|
@@ -2005,6 +2071,9 @@ function createCheckConstraintKeyStrictFifo(schema) {
|
|
|
2005
2071
|
function createIndexJobGroupConcurrency(schema) {
|
|
2006
2072
|
return `CREATE INDEX job_i7 ON ${schema}.job (name, group_id) WHERE state = '${JOB_STATES.active}' AND group_id IS NOT NULL`;
|
|
2007
2073
|
}
|
|
2074
|
+
function createIndexJobBlocking(schema) {
|
|
2075
|
+
return `CREATE INDEX job_i9 ON ${schema}.job (name, id) WHERE blocking AND state = '${JOB_STATES.completed}'`;
|
|
2076
|
+
}
|
|
2008
2077
|
function trySetQueueMonitorTime(schema, queues, seconds) {
|
|
2009
2078
|
return trySetQueueTimestamp(schema, queues, "monitor_on", seconds);
|
|
2010
2079
|
}
|
|
@@ -2017,6 +2086,9 @@ function trySetCronTime(schema, seconds) {
|
|
|
2017
2086
|
function trySetBamTime(schema, seconds) {
|
|
2018
2087
|
return trySetTimestamp(schema, "bam_on", seconds);
|
|
2019
2088
|
}
|
|
2089
|
+
function trySetFlowTime(schema, seconds) {
|
|
2090
|
+
return trySetTimestamp(schema, "flow_on", seconds);
|
|
2091
|
+
}
|
|
2020
2092
|
function trySetTimestamp(schema, column, seconds) {
|
|
2021
2093
|
return `
|
|
2022
2094
|
UPDATE ${schema}.version
|
|
@@ -2054,6 +2126,7 @@ function updateQueue(schema, { deadLetter } = {}) {
|
|
|
2054
2126
|
heartbeat_seconds = CASE WHEN o.data ? 'heartbeatSeconds'
|
|
2055
2127
|
THEN (o.data->>'heartbeatSeconds')::int
|
|
2056
2128
|
ELSE heartbeat_seconds END,
|
|
2129
|
+
notify = COALESCE((o.data->>'notify')::bool, notify),
|
|
2057
2130
|
${deadLetter === void 0 ? "" : `dead_letter = CASE WHEN '${deadLetter}' IS DISTINCT FROM dead_letter THEN '${deadLetter}' ELSE dead_letter END,`}
|
|
2058
2131
|
updated_on = now()
|
|
2059
2132
|
FROM options o
|
|
@@ -2076,11 +2149,14 @@ function getQueues$1(schema, names) {
|
|
|
2076
2149
|
q.deletion_seconds as "deleteAfterSeconds",
|
|
2077
2150
|
q.partition,
|
|
2078
2151
|
q.heartbeat_seconds as "heartbeatSeconds",
|
|
2152
|
+
q.notify,
|
|
2079
2153
|
q.dead_letter as "deadLetter",
|
|
2080
2154
|
q.deferred_count as "deferredCount",
|
|
2081
2155
|
q.warning_queued as "warningQueueSize",
|
|
2082
2156
|
q.queued_count as "queuedCount",
|
|
2157
|
+
q.ready_count as "readyCount",
|
|
2083
2158
|
q.active_count as "activeCount",
|
|
2159
|
+
q.failed_count as "failedCount",
|
|
2084
2160
|
q.total_count as "totalCount",
|
|
2085
2161
|
q.singletons_active as "singletonsActive",
|
|
2086
2162
|
q.table_name as "table",
|
|
@@ -2097,7 +2173,7 @@ function deleteJobsById(schema, table) {
|
|
|
2097
2173
|
WITH results as (
|
|
2098
2174
|
DELETE FROM ${schema}.${table}
|
|
2099
2175
|
WHERE name = $1
|
|
2100
|
-
AND id
|
|
2176
|
+
AND id = ANY($2::uuid[])
|
|
2101
2177
|
RETURNING 1
|
|
2102
2178
|
)
|
|
2103
2179
|
SELECT COUNT(*) from results
|
|
@@ -2360,7 +2436,7 @@ function completeJobsUpdate(schema, table, includeQueued) {
|
|
|
2360
2436
|
blocked = ${includeQueued ? "false" : "blocked"},
|
|
2361
2437
|
pending_dependencies = ${includeQueued ? "0" : "pending_dependencies"}
|
|
2362
2438
|
WHERE name = $1
|
|
2363
|
-
AND id
|
|
2439
|
+
AND id = ANY($2::uuid[])
|
|
2364
2440
|
AND ${includeQueued ? `state < '${JOB_STATES.completed}'` : `state = '${JOB_STATES.active}'`}`;
|
|
2365
2441
|
}
|
|
2366
2442
|
function lockedChildrenCte(schema) {
|
|
@@ -2384,24 +2460,46 @@ function unblockChildrenUpdate(schema) {
|
|
|
2384
2460
|
}
|
|
2385
2461
|
function completeJobs(schema, table, includeQueued) {
|
|
2386
2462
|
return `
|
|
2387
|
-
WITH
|
|
2463
|
+
WITH results AS (
|
|
2388
2464
|
${completeJobsUpdate(schema, table, includeQueued)}
|
|
2389
|
-
RETURNING
|
|
2390
|
-
)
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2465
|
+
RETURNING 1
|
|
2466
|
+
)
|
|
2467
|
+
SELECT COUNT(*) FROM results
|
|
2468
|
+
`;
|
|
2469
|
+
}
|
|
2470
|
+
function completeJobsWithOutputs(schema, table) {
|
|
2471
|
+
return `
|
|
2472
|
+
WITH input AS (
|
|
2473
|
+
SELECT * FROM json_to_recordset($2::json) AS x (id uuid, output jsonb)
|
|
2398
2474
|
),
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2475
|
+
results AS (
|
|
2476
|
+
UPDATE ${schema}.${table} j
|
|
2477
|
+
SET completed_on = now(),
|
|
2478
|
+
state = '${JOB_STATES.completed}',
|
|
2479
|
+
output = i.output
|
|
2480
|
+
FROM input i
|
|
2481
|
+
WHERE j.name = $1
|
|
2482
|
+
AND j.id = i.id
|
|
2483
|
+
AND j.state = '${JOB_STATES.active}'
|
|
2402
2484
|
RETURNING 1
|
|
2403
2485
|
)
|
|
2404
|
-
SELECT COUNT(*) FROM
|
|
2486
|
+
SELECT COUNT(*) FROM results
|
|
2487
|
+
`;
|
|
2488
|
+
}
|
|
2489
|
+
function completeJobsWithOutputsDistributed(schema, table) {
|
|
2490
|
+
return `
|
|
2491
|
+
WITH input AS (
|
|
2492
|
+
SELECT * FROM json_to_recordset($2::json) AS x (id uuid, output jsonb)
|
|
2493
|
+
)
|
|
2494
|
+
UPDATE ${schema}.${table} j
|
|
2495
|
+
SET completed_on = now(),
|
|
2496
|
+
state = '${JOB_STATES.completed}',
|
|
2497
|
+
output = i.output
|
|
2498
|
+
FROM input i
|
|
2499
|
+
WHERE j.name = $1
|
|
2500
|
+
AND j.id = i.id
|
|
2501
|
+
AND j.state = '${JOB_STATES.active}'
|
|
2502
|
+
RETURNING j.id
|
|
2405
2503
|
`;
|
|
2406
2504
|
}
|
|
2407
2505
|
function cancelJobs(schema, table) {
|
|
@@ -2411,7 +2509,7 @@ function cancelJobs(schema, table) {
|
|
|
2411
2509
|
SET completed_on = now(),
|
|
2412
2510
|
state = '${JOB_STATES.cancelled}'
|
|
2413
2511
|
WHERE name = $1
|
|
2414
|
-
AND id
|
|
2512
|
+
AND id = ANY($2::uuid[])
|
|
2415
2513
|
AND state < '${JOB_STATES.completed}'
|
|
2416
2514
|
RETURNING 1
|
|
2417
2515
|
)
|
|
@@ -2425,7 +2523,7 @@ function resumeJobs(schema, table) {
|
|
|
2425
2523
|
SET completed_on = NULL,
|
|
2426
2524
|
state = '${JOB_STATES.created}'
|
|
2427
2525
|
WHERE name = $1
|
|
2428
|
-
AND id
|
|
2526
|
+
AND id = ANY($2::uuid[])
|
|
2429
2527
|
AND state = '${JOB_STATES.cancelled}'
|
|
2430
2528
|
RETURNING 1
|
|
2431
2529
|
)
|
|
@@ -2439,11 +2537,11 @@ function restoreJobs(schema, table) {
|
|
|
2439
2537
|
started_on = NULL,
|
|
2440
2538
|
heartbeat_on = NULL
|
|
2441
2539
|
WHERE name = $1
|
|
2442
|
-
AND id
|
|
2540
|
+
AND id = ANY($2::uuid[])
|
|
2443
2541
|
`;
|
|
2444
2542
|
}
|
|
2445
|
-
function insertJobs(schema, { table, name, returnId = true }) {
|
|
2446
|
-
|
|
2543
|
+
function insertJobs(schema, { table, name, returnId = true, notify = false }) {
|
|
2544
|
+
const insert = `
|
|
2447
2545
|
INSERT INTO ${schema}.${table} (
|
|
2448
2546
|
id,
|
|
2449
2547
|
name,
|
|
@@ -2526,11 +2624,35 @@ function insertJobs(schema, { table, name, returnId = true }) {
|
|
|
2526
2624
|
) j
|
|
2527
2625
|
JOIN ${schema}.queue q ON q.name = '${name}'
|
|
2528
2626
|
ON CONFLICT DO NOTHING
|
|
2529
|
-
${returnId ? "RETURNING id" : ""}
|
|
2627
|
+
${notify ? "RETURNING id, start_after" : returnId ? "RETURNING id" : ""}
|
|
2628
|
+
`;
|
|
2629
|
+
if (!notify) return insert;
|
|
2630
|
+
const comparator = returnId ? ">= 0" : "< 0";
|
|
2631
|
+
return `
|
|
2632
|
+
WITH ins AS (
|
|
2633
|
+
${insert}
|
|
2634
|
+
),
|
|
2635
|
+
notified AS (
|
|
2636
|
+
SELECT pg_notify(${notifyChannelSql(schema)}, '${name}')
|
|
2637
|
+
FROM ins WHERE start_after <= now() LIMIT 1
|
|
2638
|
+
)
|
|
2639
|
+
SELECT id FROM ins WHERE (SELECT count(*) FROM notified) ${comparator}
|
|
2640
|
+
`;
|
|
2641
|
+
}
|
|
2642
|
+
function insertFlowJobs(schema, { table, name }, jobs) {
|
|
2643
|
+
return `
|
|
2644
|
+
WITH ins AS (
|
|
2645
|
+
${insertJobs(schema, {
|
|
2646
|
+
table,
|
|
2647
|
+
name,
|
|
2648
|
+
returnId: true
|
|
2649
|
+
}).replace("$1", () => serializeJsonParam(jobs))}
|
|
2650
|
+
)
|
|
2651
|
+
SELECT 1 / (CASE WHEN (SELECT count(*) FROM ins) = ${jobs.length} THEN 1 ELSE 0 END)
|
|
2530
2652
|
`;
|
|
2531
2653
|
}
|
|
2532
2654
|
function failJobsById(schema, table) {
|
|
2533
|
-
return failJobs(schema, table, `name = $1 AND id
|
|
2655
|
+
return failJobs(schema, table, `name = $1 AND id = ANY($2::uuid[]) AND state < '${JOB_STATES.completed}'`, "$3::jsonb");
|
|
2534
2656
|
}
|
|
2535
2657
|
function failJobsByTimeout(schema, table, queues, noAdvisoryLocks) {
|
|
2536
2658
|
return locked(schema, failJobs(schema, table, `state = '${JOB_STATES.active}'
|
|
@@ -2549,7 +2671,7 @@ function touchJobs(schema, table) {
|
|
|
2549
2671
|
UPDATE ${schema}.${table}
|
|
2550
2672
|
SET heartbeat_on = now()
|
|
2551
2673
|
WHERE name = $1
|
|
2552
|
-
AND id
|
|
2674
|
+
AND id = ANY($2::uuid[])
|
|
2553
2675
|
AND state = '${JOB_STATES.active}'
|
|
2554
2676
|
RETURNING 1
|
|
2555
2677
|
)
|
|
@@ -2558,7 +2680,12 @@ function touchJobs(schema, table) {
|
|
|
2558
2680
|
}
|
|
2559
2681
|
function failJobs(schema, table, where, output) {
|
|
2560
2682
|
return `
|
|
2561
|
-
WITH
|
|
2683
|
+
WITH ${failJobsBody(schema, table, where, output)}
|
|
2684
|
+
SELECT COUNT(*) FROM results
|
|
2685
|
+
`;
|
|
2686
|
+
}
|
|
2687
|
+
function failJobsBody(schema, table, where, output, forceTerminal = false) {
|
|
2688
|
+
return `deleted_jobs AS (
|
|
2562
2689
|
DELETE FROM ${schema}.${table}
|
|
2563
2690
|
WHERE ${where}
|
|
2564
2691
|
RETURNING *
|
|
@@ -2600,10 +2727,10 @@ function failJobs(schema, table, where, output) {
|
|
|
2600
2727
|
name,
|
|
2601
2728
|
priority,
|
|
2602
2729
|
data,
|
|
2603
|
-
CASE
|
|
2730
|
+
${forceTerminal ? `'${JOB_STATES.failed}'::${schema}.job_state` : `CASE
|
|
2604
2731
|
WHEN retry_count < retry_limit THEN '${JOB_STATES.retry}'::${schema}.job_state
|
|
2605
2732
|
ELSE '${JOB_STATES.failed}'::${schema}.job_state
|
|
2606
|
-
END as state,
|
|
2733
|
+
END`} as state,
|
|
2607
2734
|
retry_limit,
|
|
2608
2735
|
retry_count,
|
|
2609
2736
|
retry_delay,
|
|
@@ -2627,7 +2754,7 @@ function failJobs(schema, table, where, output) {
|
|
|
2627
2754
|
expire_seconds,
|
|
2628
2755
|
deletion_seconds,
|
|
2629
2756
|
created_on,
|
|
2630
|
-
CASE WHEN retry_count < retry_limit THEN NULL ELSE now() END as completed_on,
|
|
2757
|
+
${forceTerminal ? "now()" : "CASE WHEN retry_count < retry_limit THEN NULL ELSE now() END"} as completed_on,
|
|
2631
2758
|
keep_until,
|
|
2632
2759
|
policy,
|
|
2633
2760
|
${output},
|
|
@@ -2726,19 +2853,35 @@ function failJobs(schema, table, where, output) {
|
|
|
2726
2853
|
FROM results r
|
|
2727
2854
|
JOIN ${schema}.queue q ON q.name = r.dead_letter
|
|
2728
2855
|
WHERE state = '${JOB_STATES.failed}'
|
|
2729
|
-
)
|
|
2856
|
+
)`;
|
|
2857
|
+
}
|
|
2858
|
+
function failJobsByIdWithOutputs(schema, table) {
|
|
2859
|
+
return `
|
|
2860
|
+
WITH output_map AS (
|
|
2861
|
+
SELECT * FROM json_to_recordset($2::json) AS x (id uuid, output jsonb)
|
|
2862
|
+
),
|
|
2863
|
+
${failJobsBody(schema, table, `name = $1 AND id IN (SELECT id FROM output_map) AND state < '${JOB_STATES.completed}'`, "(SELECT om.output FROM output_map om WHERE om.id = deleted_jobs.id)")}
|
|
2864
|
+
SELECT COUNT(*) FROM results
|
|
2865
|
+
`;
|
|
2866
|
+
}
|
|
2867
|
+
function deadLetterJobsByIdWithOutputs(schema, table) {
|
|
2868
|
+
return `
|
|
2869
|
+
WITH output_map AS (
|
|
2870
|
+
SELECT * FROM json_to_recordset($2::json) AS x (id uuid, output jsonb)
|
|
2871
|
+
),
|
|
2872
|
+
${failJobsBody(schema, table, `name = $1 AND id IN (SELECT id FROM output_map) AND state < '${JOB_STATES.completed}'`, "(SELECT om.output FROM output_map om WHERE om.id = deleted_jobs.id)", true)}
|
|
2730
2873
|
SELECT COUNT(*) FROM results
|
|
2731
2874
|
`;
|
|
2732
2875
|
}
|
|
2733
2876
|
function selectJobsToFailById(schema, table) {
|
|
2734
2877
|
return {
|
|
2735
|
-
text: `SELECT * FROM ${schema}.${table} WHERE name = $1 AND id
|
|
2878
|
+
text: `SELECT * FROM ${schema}.${table} WHERE name = $1 AND id = ANY($2::uuid[]) AND state < '${JOB_STATES.completed}'`,
|
|
2736
2879
|
values: []
|
|
2737
2880
|
};
|
|
2738
2881
|
}
|
|
2739
2882
|
function deleteJobsToFail(schema, table) {
|
|
2740
2883
|
return {
|
|
2741
|
-
text: `DELETE FROM ${schema}.${table} WHERE name = $1 AND id
|
|
2884
|
+
text: `DELETE FROM ${schema}.${table} WHERE name = $1 AND id = ANY($2::uuid[])`,
|
|
2742
2885
|
values: []
|
|
2743
2886
|
};
|
|
2744
2887
|
}
|
|
@@ -2763,14 +2906,14 @@ function selectJobsToFailByHeartbeat(schema, table, queues) {
|
|
|
2763
2906
|
}
|
|
2764
2907
|
function deleteJobsByIds(schema, table) {
|
|
2765
2908
|
return {
|
|
2766
|
-
text: `DELETE FROM ${schema}.${table} WHERE id
|
|
2909
|
+
text: `DELETE FROM ${schema}.${table} WHERE id = ANY($1::uuid[])`,
|
|
2767
2910
|
values: []
|
|
2768
2911
|
};
|
|
2769
2912
|
}
|
|
2770
2913
|
function completeJobsDistributed(schema, table, includeQueued) {
|
|
2771
2914
|
return `
|
|
2772
2915
|
${completeJobsUpdate(schema, table, includeQueued)}
|
|
2773
|
-
RETURNING id
|
|
2916
|
+
RETURNING id
|
|
2774
2917
|
`;
|
|
2775
2918
|
}
|
|
2776
2919
|
function decrementDependents(schema) {
|
|
@@ -2779,13 +2922,75 @@ function decrementDependents(schema) {
|
|
|
2779
2922
|
SELECT d.child_name, d.child_id, COUNT(*)::int AS n
|
|
2780
2923
|
FROM ${schema}.job_dependency d
|
|
2781
2924
|
WHERE d.parent_name = $1
|
|
2782
|
-
AND d.parent_id
|
|
2925
|
+
AND d.parent_id = ANY($2::uuid[])
|
|
2783
2926
|
GROUP BY d.child_name, d.child_id
|
|
2784
2927
|
),
|
|
2785
2928
|
${lockedChildrenCte(schema)}
|
|
2786
2929
|
${unblockChildrenUpdate(schema)}
|
|
2787
2930
|
`;
|
|
2788
2931
|
}
|
|
2932
|
+
var FLOW_BATCH_SIZE = 1e3;
|
|
2933
|
+
function resolveFlowJobs(schema, table, names) {
|
|
2934
|
+
return {
|
|
2935
|
+
text: `
|
|
2936
|
+
WITH locked_parents AS (
|
|
2937
|
+
SELECT j.name, j.id
|
|
2938
|
+
FROM ${schema}.${table} j
|
|
2939
|
+
WHERE j.blocking
|
|
2940
|
+
AND j.state = '${JOB_STATES.completed}'
|
|
2941
|
+
AND j.name = ANY($1::text[])
|
|
2942
|
+
ORDER BY j.name, j.id
|
|
2943
|
+
FOR UPDATE OF j SKIP LOCKED
|
|
2944
|
+
LIMIT ${FLOW_BATCH_SIZE}
|
|
2945
|
+
),
|
|
2946
|
+
decremented AS (
|
|
2947
|
+
SELECT d.child_name, d.child_id, COUNT(*)::int AS n
|
|
2948
|
+
FROM ${schema}.job_dependency d
|
|
2949
|
+
JOIN locked_parents p ON d.parent_name = p.name
|
|
2950
|
+
AND d.parent_id = p.id
|
|
2951
|
+
GROUP BY d.child_name, d.child_id
|
|
2952
|
+
),
|
|
2953
|
+
${lockedChildrenCte(schema)},
|
|
2954
|
+
unblocked AS (
|
|
2955
|
+
${unblockChildrenUpdate(schema)}
|
|
2956
|
+
RETURNING 1
|
|
2957
|
+
),
|
|
2958
|
+
cleared AS (
|
|
2959
|
+
UPDATE ${schema}.${table} j
|
|
2960
|
+
SET blocking = false
|
|
2961
|
+
FROM locked_parents p
|
|
2962
|
+
WHERE j.name = p.name
|
|
2963
|
+
AND j.id = p.id
|
|
2964
|
+
RETURNING 1
|
|
2965
|
+
)
|
|
2966
|
+
SELECT COUNT(*)::int AS resolved FROM cleared
|
|
2967
|
+
`,
|
|
2968
|
+
values: [names]
|
|
2969
|
+
};
|
|
2970
|
+
}
|
|
2971
|
+
function selectBlockingParents(schema, table, names, noSkipLocked) {
|
|
2972
|
+
return {
|
|
2973
|
+
text: `
|
|
2974
|
+
SELECT name, id
|
|
2975
|
+
FROM ${schema}.${table}
|
|
2976
|
+
WHERE blocking
|
|
2977
|
+
AND state = '${JOB_STATES.completed}'
|
|
2978
|
+
AND name = ANY($1::text[])
|
|
2979
|
+
ORDER BY name, id
|
|
2980
|
+
FOR UPDATE${noSkipLocked ? "" : " SKIP LOCKED"}
|
|
2981
|
+
LIMIT ${FLOW_BATCH_SIZE}
|
|
2982
|
+
`,
|
|
2983
|
+
values: [names]
|
|
2984
|
+
};
|
|
2985
|
+
}
|
|
2986
|
+
function clearBlocking(schema) {
|
|
2987
|
+
return `
|
|
2988
|
+
UPDATE ${schema}.job
|
|
2989
|
+
SET blocking = false
|
|
2990
|
+
WHERE name = $1
|
|
2991
|
+
AND id = ANY($2::uuid[])
|
|
2992
|
+
`;
|
|
2993
|
+
}
|
|
2789
2994
|
function insertRetryJob(schema, table) {
|
|
2790
2995
|
return `
|
|
2791
2996
|
INSERT INTO ${schema}.${table} (
|
|
@@ -2827,7 +3032,7 @@ function retryJobs(schema, table) {
|
|
|
2827
3032
|
SET state = '${JOB_STATES.retry}',
|
|
2828
3033
|
retry_limit = retry_limit + 1
|
|
2829
3034
|
WHERE name = $1
|
|
2830
|
-
AND id
|
|
3035
|
+
AND id = ANY($2::uuid[])
|
|
2831
3036
|
AND state = '${JOB_STATES.failed}'
|
|
2832
3037
|
RETURNING 1
|
|
2833
3038
|
)
|
|
@@ -2839,14 +3044,26 @@ function getQueueStats$1(schema, table, queues) {
|
|
|
2839
3044
|
text: `
|
|
2840
3045
|
SELECT
|
|
2841
3046
|
name,
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
(
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
3047
|
+
"deferredCount",
|
|
3048
|
+
"queuedCount",
|
|
3049
|
+
GREATEST("queuedCount" - "deferredCount", 0) as "readyCount",
|
|
3050
|
+
"activeCount",
|
|
3051
|
+
"failedCount",
|
|
3052
|
+
"totalCount",
|
|
3053
|
+
"singletonsActive"
|
|
3054
|
+
FROM (
|
|
3055
|
+
SELECT
|
|
3056
|
+
name,
|
|
3057
|
+
(count(*) FILTER (WHERE start_after > now()))::int as "deferredCount",
|
|
3058
|
+
(count(*) FILTER (WHERE state < '${JOB_STATES.active}'))::int as "queuedCount",
|
|
3059
|
+
(count(*) FILTER (WHERE state = '${JOB_STATES.active}'))::int as "activeCount",
|
|
3060
|
+
(count(*) FILTER (WHERE state = '${JOB_STATES.failed}'))::int as "failedCount",
|
|
3061
|
+
count(*)::int as "totalCount",
|
|
3062
|
+
array_agg(singleton_key) FILTER (WHERE policy IN ('${QUEUE_POLICIES.singleton}','${QUEUE_POLICIES.stately}') AND state = '${JOB_STATES.active}') as "singletonsActive"
|
|
3063
|
+
FROM ${schema}.${table}
|
|
3064
|
+
WHERE name = ANY($1::text[])
|
|
3065
|
+
GROUP BY 1
|
|
3066
|
+
) stats
|
|
2850
3067
|
`,
|
|
2851
3068
|
values: [queues]
|
|
2852
3069
|
};
|
|
@@ -2857,7 +3074,9 @@ function cacheQueueStats(schema, table, queues, noAdvisoryLocks) {
|
|
|
2857
3074
|
UPDATE ${schema}.queue SET
|
|
2858
3075
|
deferred_count = COALESCE(stats."deferredCount", 0),
|
|
2859
3076
|
queued_count = COALESCE(stats."queuedCount", 0),
|
|
3077
|
+
ready_count = COALESCE(stats."readyCount", 0),
|
|
2860
3078
|
active_count = COALESCE(stats."activeCount", 0),
|
|
3079
|
+
failed_count = COALESCE(stats."failedCount", 0),
|
|
2861
3080
|
total_count = COALESCE(stats."totalCount", 0),
|
|
2862
3081
|
singletons_active = stats."singletonsActive"
|
|
2863
3082
|
FROM (
|
|
@@ -2931,8 +3150,8 @@ function getJobById$1(schema, table) {
|
|
|
2931
3150
|
AND id = $2
|
|
2932
3151
|
`;
|
|
2933
3152
|
}
|
|
2934
|
-
function insertDependencies(schema) {
|
|
2935
|
-
|
|
3153
|
+
function insertDependencies(schema, deps) {
|
|
3154
|
+
const sql = `
|
|
2936
3155
|
INSERT INTO ${schema}.job_dependency (child_name, child_id, parent_name, parent_id)
|
|
2937
3156
|
SELECT child_name, child_id, parent_name, parent_id
|
|
2938
3157
|
FROM json_to_recordset($1::json) AS x (
|
|
@@ -2943,6 +3162,7 @@ function insertDependencies(schema) {
|
|
|
2943
3162
|
)
|
|
2944
3163
|
ON CONFLICT DO NOTHING
|
|
2945
3164
|
`;
|
|
3165
|
+
return deps ? sql.replace("$1", () => serializeJsonParam(deps)) : sql;
|
|
2946
3166
|
}
|
|
2947
3167
|
function getDependencies(schema) {
|
|
2948
3168
|
return `
|
|
@@ -3018,7 +3238,7 @@ function getBamStatus(schema) {
|
|
|
3018
3238
|
GROUP BY status
|
|
3019
3239
|
`;
|
|
3020
3240
|
}
|
|
3021
|
-
function getBamEntries(schema) {
|
|
3241
|
+
function getBamEntries$1(schema) {
|
|
3022
3242
|
return `
|
|
3023
3243
|
SELECT id, name, version, status, queue, table_name as "table", command, error,
|
|
3024
3244
|
created_on as "createdOn", started_on as "startedOn", completed_on as "completedOn"
|
|
@@ -3039,7 +3259,8 @@ var COMPATIBILITY_FLAGS = [
|
|
|
3039
3259
|
"noTablePartitioning",
|
|
3040
3260
|
"noDeferrableConstraints",
|
|
3041
3261
|
"noAdvisoryLocks",
|
|
3042
|
-
"noCoveringIndexes"
|
|
3262
|
+
"noCoveringIndexes",
|
|
3263
|
+
"noListenNotify"
|
|
3043
3264
|
];
|
|
3044
3265
|
var BACKEND_PROFILES = {
|
|
3045
3266
|
postgres: {
|
|
@@ -3054,7 +3275,8 @@ var BACKEND_PROFILES = {
|
|
|
3054
3275
|
noTablePartitioning: true,
|
|
3055
3276
|
noDeferrableConstraints: true,
|
|
3056
3277
|
noAdvisoryLocks: true,
|
|
3057
|
-
noCoveringIndexes: true
|
|
3278
|
+
noCoveringIndexes: true,
|
|
3279
|
+
noListenNotify: true
|
|
3058
3280
|
}
|
|
3059
3281
|
},
|
|
3060
3282
|
yugabytedb: {
|
|
@@ -3078,6 +3300,7 @@ function assertObjectName(value, name = "Name") {
|
|
|
3078
3300
|
}
|
|
3079
3301
|
function validateQueueArgs(config = {}) {
|
|
3080
3302
|
assert(!("deadLetter" in config) || config.deadLetter === null || typeof config.deadLetter === "string", "deadLetter must be a string");
|
|
3303
|
+
assert(!("notify" in config) || typeof config.notify === "boolean", "notify must be a boolean");
|
|
3081
3304
|
if (config.deadLetter) assertObjectName(config.deadLetter, "deadLetter");
|
|
3082
3305
|
validateRetryConfig(config);
|
|
3083
3306
|
validateExpirationConfig(config);
|
|
@@ -3257,6 +3480,7 @@ function checkWorkArgs(name, args) {
|
|
|
3257
3480
|
assert(!("includeMetadata" in options) || typeof options.includeMetadata === "boolean", "includeMetadata must be a boolean");
|
|
3258
3481
|
assert(!("priority" in options) || typeof options.priority === "boolean", "priority must be a boolean");
|
|
3259
3482
|
assert(!("localConcurrency" in options) || Number.isInteger(options.localConcurrency) && options.localConcurrency >= 1, "localConcurrency must be an integer >= 1");
|
|
3483
|
+
assert(!("perJobResults" in options) || typeof options.perJobResults === "boolean", "perJobResults must be a boolean");
|
|
3260
3484
|
validatePriorityRangeConfig(options);
|
|
3261
3485
|
validateGroupConcurrencyConfig(options);
|
|
3262
3486
|
validateHeartbeatRefreshConfig(options);
|
|
@@ -3280,11 +3504,13 @@ function getConfig(value) {
|
|
|
3280
3504
|
config.supervise = "supervise" in config ? config.supervise : true;
|
|
3281
3505
|
config.migrate = "migrate" in config ? config.migrate : true;
|
|
3282
3506
|
config.createSchema = "createSchema" in config ? config.createSchema : true;
|
|
3507
|
+
config.useListenNotify = "useListenNotify" in config ? config.useListenNotify : false;
|
|
3283
3508
|
resolveBackend(config);
|
|
3284
3509
|
applySchemaConfig(config);
|
|
3285
3510
|
applyOpsConfig(config);
|
|
3286
3511
|
applyScheduleConfig(config);
|
|
3287
3512
|
applyBamConfig(config);
|
|
3513
|
+
applyFlowConfig(config);
|
|
3288
3514
|
validateWarningConfig(config);
|
|
3289
3515
|
return config;
|
|
3290
3516
|
}
|
|
@@ -3349,6 +3575,13 @@ function validateHeartbeatRefreshConfig(config) {
|
|
|
3349
3575
|
function applyPollingInterval(config) {
|
|
3350
3576
|
assert(!("pollingIntervalSeconds" in config) || config.pollingIntervalSeconds >= POLICY.MIN_POLLING_INTERVAL_MS / 1e3, `configuration assert: pollingIntervalSeconds must be at least every ${POLICY.MIN_POLLING_INTERVAL_MS}ms`);
|
|
3351
3577
|
config.pollingInterval = "pollingIntervalSeconds" in config ? config.pollingIntervalSeconds * 1e3 : 2e3;
|
|
3578
|
+
assert(!("notifyPollingIntervalSeconds" in config) || config.notifyPollingIntervalSeconds >= POLICY.MIN_POLLING_INTERVAL_MS / 1e3, `configuration assert: notifyPollingIntervalSeconds must be at least every ${POLICY.MIN_POLLING_INTERVAL_MS}ms`);
|
|
3579
|
+
if ("notifyPollingIntervalSeconds" in config) {
|
|
3580
|
+
config.notifyPollingInterval = config.notifyPollingIntervalSeconds * 1e3;
|
|
3581
|
+
assert(config.notifyPollingInterval >= config.pollingInterval, "configuration assert: notifyPollingIntervalSeconds must be at least pollingIntervalSeconds");
|
|
3582
|
+
} else config.notifyPollingInterval = Math.max(3e4, config.pollingInterval);
|
|
3583
|
+
assert(!("burstWhenReadyExceeds" in config) || Number.isInteger(config.burstWhenReadyExceeds) && config.burstWhenReadyExceeds >= 1, "configuration assert: burstWhenReadyExceeds must be an integer >= 1");
|
|
3584
|
+
assert(!("burstWhenBatchFull" in config) || typeof config.burstWhenBatchFull === "boolean", "configuration assert: burstWhenBatchFull must be a boolean");
|
|
3352
3585
|
}
|
|
3353
3586
|
function applyOpsConfig(config) {
|
|
3354
3587
|
assert(!("superviseIntervalSeconds" in config) || config.superviseIntervalSeconds >= 1, "configuration assert: superviseIntervalSeconds must be at least every second");
|
|
@@ -3380,8 +3613,28 @@ function applyBamConfig(config) {
|
|
|
3380
3613
|
assert(!("bamIntervalSeconds" in config) || config.bamIntervalSeconds >= minInterval, `configuration assert: bamIntervalSeconds must be at least ${minInterval} seconds`);
|
|
3381
3614
|
config.bamIntervalSeconds = config.bamIntervalSeconds || 60;
|
|
3382
3615
|
}
|
|
3616
|
+
function applyFlowConfig(config) {
|
|
3617
|
+
const minInterval = config.__test__bypass_flow_interval_check ? .5 : 1;
|
|
3618
|
+
assert(!("flowIntervalSeconds" in config) || config.flowIntervalSeconds >= minInterval, `configuration assert: flowIntervalSeconds must be at least ${minInterval} seconds`);
|
|
3619
|
+
config.flowIntervalSeconds = config.flowIntervalSeconds || 5;
|
|
3620
|
+
}
|
|
3383
3621
|
//#endregion
|
|
3384
3622
|
//#region ../../src/migrationStore.ts
|
|
3623
|
+
function formatJobTable(command, table) {
|
|
3624
|
+
return command.replaceAll(".job", `.${table}`).replaceAll("job_i", `${table}_i`);
|
|
3625
|
+
}
|
|
3626
|
+
function inlineAsyncCommand(schema, asyncCommand, version, partitionTables) {
|
|
3627
|
+
const nameMatch = asyncCommand.match(/job_table_run_async\(\s*'([^']+)'/);
|
|
3628
|
+
const bodyMatch = asyncCommand.match(/\$\$([\s\S]*?)\$\$/);
|
|
3629
|
+
const tableMatch = asyncCommand.match(/\$\$\s*,\s*'([^']+)'/);
|
|
3630
|
+
assert(nameMatch && bodyMatch, `Unable to inline async migration command: ${asyncCommand}`);
|
|
3631
|
+
const commandName = nameMatch[1];
|
|
3632
|
+
const body = bodyMatch[1].trim();
|
|
3633
|
+
return (tableMatch ? [tableMatch[1]] : ["job_common", ...partitionTables]).map((table) => {
|
|
3634
|
+
const ddl = formatJobTable(body, table).replace(/(CREATE (?:UNIQUE )?INDEX CONCURRENTLY) /, "$1 IF NOT EXISTS ");
|
|
3635
|
+
return `${`-- inlined from ${schema}.job_table_run_async (migration v${version}, command: ${commandName})`}\n${ddl}`;
|
|
3636
|
+
});
|
|
3637
|
+
}
|
|
3385
3638
|
function flatten(schema, commands, version, noAdvisoryLocks) {
|
|
3386
3639
|
commands.unshift(assertMigration(schema, version));
|
|
3387
3640
|
commands.push(setVersion(schema, version));
|
|
@@ -3399,11 +3652,13 @@ function next(schema, version, migrations, noAdvisoryLocks) {
|
|
|
3399
3652
|
assert(result, `Version ${version} not found.`);
|
|
3400
3653
|
return flatten(schema, result.install, result.version, noAdvisoryLocks);
|
|
3401
3654
|
}
|
|
3402
|
-
function
|
|
3655
|
+
function migrateCommands(schema, version, migrations, noAdvisoryLocks, options = {}) {
|
|
3403
3656
|
migrations = migrations || getAll(schema);
|
|
3657
|
+
const concurrent = [];
|
|
3404
3658
|
const result = migrations.filter((i) => i.previous >= version).sort((a, b) => a.version - b.version).reduce((acc, migration) => {
|
|
3405
3659
|
acc.install = acc.install.concat(migration.install);
|
|
3406
|
-
if (migration.async)
|
|
3660
|
+
if (migration.async) if (options.inlineAsync) for (const cmd of migration.async) concurrent.push(...inlineAsyncCommand(schema, cmd, migration.version, options.partitionTables || []));
|
|
3661
|
+
else {
|
|
3407
3662
|
const bamCommands = migration.async.map((cmd) => cmd.replace(/\$VERSION\$/g, String(migration.version)));
|
|
3408
3663
|
acc.install = acc.install.concat(bamCommands);
|
|
3409
3664
|
}
|
|
@@ -3414,151 +3669,657 @@ function migrate(schema, version, migrations, noAdvisoryLocks) {
|
|
|
3414
3669
|
version
|
|
3415
3670
|
});
|
|
3416
3671
|
assert(result.install.length > 0, `Version ${version} not found.`);
|
|
3417
|
-
return
|
|
3672
|
+
return {
|
|
3673
|
+
sql: flatten(schema, result.install, result.version, noAdvisoryLocks),
|
|
3674
|
+
concurrent
|
|
3675
|
+
};
|
|
3418
3676
|
}
|
|
3419
|
-
function
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
|
|
3426
|
-
|
|
3427
|
-
|
|
3428
|
-
|
|
3429
|
-
|
|
3430
|
-
|
|
3431
|
-
|
|
3432
|
-
|
|
3433
|
-
|
|
3434
|
-
|
|
3435
|
-
BEGIN
|
|
3436
|
-
|
|
3437
|
-
WITH q as (
|
|
3438
|
-
INSERT INTO ${schema}.queue (
|
|
3439
|
-
name,
|
|
3440
|
-
policy,
|
|
3441
|
-
retry_limit,
|
|
3442
|
-
retry_delay,
|
|
3443
|
-
retry_backoff,
|
|
3444
|
-
retry_delay_max,
|
|
3445
|
-
expire_seconds,
|
|
3446
|
-
retention_seconds,
|
|
3447
|
-
deletion_seconds,
|
|
3448
|
-
warning_queued,
|
|
3449
|
-
dead_letter,
|
|
3450
|
-
partition,
|
|
3451
|
-
table_name
|
|
3452
|
-
)
|
|
3453
|
-
VALUES (
|
|
3454
|
-
queue_name,
|
|
3455
|
-
options->>'policy',
|
|
3456
|
-
COALESCE((options->>'retryLimit')::int, 2),
|
|
3457
|
-
COALESCE((options->>'retryDelay')::int, 0),
|
|
3458
|
-
COALESCE((options->>'retryBackoff')::bool, false),
|
|
3459
|
-
(options->>'retryDelayMax')::int,
|
|
3460
|
-
COALESCE((options->>'expireInSeconds')::int, 900),
|
|
3461
|
-
COALESCE((options->>'retentionSeconds')::int, 1209600),
|
|
3462
|
-
COALESCE((options->>'deleteAfterSeconds')::int, 604800),
|
|
3463
|
-
COALESCE((options->>'warningQueueSize')::int, 0),
|
|
3464
|
-
options->>'deadLetter',
|
|
3465
|
-
COALESCE((options->>'partition')::bool, false),
|
|
3466
|
-
tablename
|
|
3467
|
-
)
|
|
3468
|
-
ON CONFLICT DO NOTHING
|
|
3469
|
-
RETURNING created_on
|
|
3470
|
-
)
|
|
3471
|
-
SELECT created_on into queue_created_on from q;
|
|
3677
|
+
function migrate(schema, version, migrations, noAdvisoryLocks, options = {}) {
|
|
3678
|
+
const { sql, concurrent } = migrateCommands(schema, version, migrations, noAdvisoryLocks, options);
|
|
3679
|
+
return concurrent.length ? `${sql}\n${concurrent.join(";\n")};` : sql;
|
|
3680
|
+
}
|
|
3681
|
+
var createQueueFn = {
|
|
3682
|
+
26: (schema) => `
|
|
3683
|
+
CREATE OR REPLACE FUNCTION ${schema}.create_queue(queue_name text, options jsonb)
|
|
3684
|
+
RETURNS VOID AS
|
|
3685
|
+
$$
|
|
3686
|
+
DECLARE
|
|
3687
|
+
tablename varchar := CASE WHEN options->>'partition' = 'true'
|
|
3688
|
+
THEN 'j' || encode(sha224(queue_name::bytea), 'hex')
|
|
3689
|
+
ELSE 'job_common'
|
|
3690
|
+
END;
|
|
3691
|
+
queue_created_on timestamptz;
|
|
3692
|
+
BEGIN
|
|
3472
3693
|
|
|
3473
|
-
|
|
3474
|
-
|
|
3475
|
-
|
|
3694
|
+
WITH q as (
|
|
3695
|
+
INSERT INTO ${schema}.queue (
|
|
3696
|
+
name,
|
|
3697
|
+
policy,
|
|
3698
|
+
retry_limit,
|
|
3699
|
+
retry_delay,
|
|
3700
|
+
retry_backoff,
|
|
3701
|
+
retry_delay_max,
|
|
3702
|
+
expire_seconds,
|
|
3703
|
+
retention_seconds,
|
|
3704
|
+
deletion_seconds,
|
|
3705
|
+
warning_queued,
|
|
3706
|
+
dead_letter,
|
|
3707
|
+
partition,
|
|
3708
|
+
table_name
|
|
3709
|
+
)
|
|
3710
|
+
VALUES (
|
|
3711
|
+
queue_name,
|
|
3712
|
+
options->>'policy',
|
|
3713
|
+
COALESCE((options->>'retryLimit')::int, 2),
|
|
3714
|
+
COALESCE((options->>'retryDelay')::int, 0),
|
|
3715
|
+
COALESCE((options->>'retryBackoff')::bool, false),
|
|
3716
|
+
(options->>'retryDelayMax')::int,
|
|
3717
|
+
COALESCE((options->>'expireInSeconds')::int, 900),
|
|
3718
|
+
COALESCE((options->>'retentionSeconds')::int, 1209600),
|
|
3719
|
+
COALESCE((options->>'deleteAfterSeconds')::int, 604800),
|
|
3720
|
+
COALESCE((options->>'warningQueueSize')::int, 0),
|
|
3721
|
+
options->>'deadLetter',
|
|
3722
|
+
COALESCE((options->>'partition')::bool, false),
|
|
3723
|
+
tablename
|
|
3724
|
+
)
|
|
3725
|
+
ON CONFLICT DO NOTHING
|
|
3726
|
+
RETURNING created_on
|
|
3727
|
+
)
|
|
3728
|
+
SELECT created_on into queue_created_on from q;
|
|
3476
3729
|
|
|
3477
|
-
|
|
3730
|
+
IF queue_created_on IS NULL OR options->>'partition' IS DISTINCT FROM 'true' THEN
|
|
3731
|
+
RETURN;
|
|
3732
|
+
END IF;
|
|
3478
3733
|
|
|
3479
|
-
|
|
3480
|
-
EXECUTE format('ALTER TABLE ${schema}.%1$I ADD CONSTRAINT q_fkey FOREIGN KEY (name) REFERENCES ${schema}.queue (name) ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED', tablename);
|
|
3481
|
-
EXECUTE format('ALTER TABLE ${schema}.%1$I ADD CONSTRAINT dlq_fkey FOREIGN KEY (dead_letter) REFERENCES ${schema}.queue (name) ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED', tablename);
|
|
3734
|
+
EXECUTE format('CREATE TABLE ${schema}.%I (LIKE ${schema}.job INCLUDING DEFAULTS)', tablename);
|
|
3482
3735
|
|
|
3483
|
-
|
|
3484
|
-
|
|
3736
|
+
EXECUTE format('ALTER TABLE ${schema}.%1$I ADD PRIMARY KEY (name, id)', tablename);
|
|
3737
|
+
EXECUTE format('ALTER TABLE ${schema}.%1$I ADD CONSTRAINT q_fkey FOREIGN KEY (name) REFERENCES ${schema}.queue (name) ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED', tablename);
|
|
3738
|
+
EXECUTE format('ALTER TABLE ${schema}.%1$I ADD CONSTRAINT dlq_fkey FOREIGN KEY (dead_letter) REFERENCES ${schema}.queue (name) ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED', tablename);
|
|
3485
3739
|
|
|
3486
|
-
|
|
3487
|
-
|
|
3488
|
-
ELSIF options->>'policy' = 'singleton' THEN
|
|
3489
|
-
EXECUTE format('CREATE UNIQUE INDEX %1$s_i2 ON ${schema}.%1$I (name, COALESCE(singleton_key, '''')) WHERE state = ''active'' AND policy = ''singleton''', tablename);
|
|
3490
|
-
ELSIF options->>'policy' = 'stately' THEN
|
|
3491
|
-
EXECUTE format('CREATE UNIQUE INDEX %1$s_i3 ON ${schema}.%1$I (name, state, COALESCE(singleton_key, '''')) WHERE state <= ''active'' AND policy = ''stately''', tablename);
|
|
3492
|
-
ELSIF options->>'policy' = 'exclusive' THEN
|
|
3493
|
-
EXECUTE format('CREATE UNIQUE INDEX %1$s_i6 ON ${schema}.%1$I (name, COALESCE(singleton_key, '''')) WHERE state <= ''active'' AND policy = ''exclusive''', tablename);
|
|
3494
|
-
END IF;
|
|
3740
|
+
EXECUTE format('CREATE INDEX %1$s_i5 ON ${schema}.%1$I (name, start_after) INCLUDE (priority, created_on, id) WHERE state < ''active''', tablename);
|
|
3741
|
+
EXECUTE format('CREATE UNIQUE INDEX %1$s_i4 ON ${schema}.%1$I (name, singleton_on, COALESCE(singleton_key, '''')) WHERE state <> ''cancelled'' AND singleton_on IS NOT NULL', tablename);
|
|
3495
3742
|
|
|
3496
|
-
|
|
3497
|
-
|
|
3498
|
-
|
|
3499
|
-
|
|
3500
|
-
|
|
3501
|
-
|
|
3502
|
-
|
|
3503
|
-
|
|
3504
|
-
|
|
3505
|
-
release: "12.6.0",
|
|
3506
|
-
version: 27,
|
|
3507
|
-
previous: 26,
|
|
3508
|
-
install: [
|
|
3509
|
-
`ALTER TABLE ${schema}.version ADD COLUMN IF NOT EXISTS bam_on timestamp with time zone`,
|
|
3510
|
-
`
|
|
3511
|
-
CREATE TABLE IF NOT EXISTS ${schema}.bam (
|
|
3512
|
-
id uuid PRIMARY KEY default gen_random_uuid(),
|
|
3513
|
-
name text NOT NULL,
|
|
3514
|
-
version int NOT NULL,
|
|
3515
|
-
status text NOT NULL DEFAULT 'pending',
|
|
3516
|
-
queue text,
|
|
3517
|
-
table_name text NOT NULL,
|
|
3518
|
-
command text NOT NULL,
|
|
3519
|
-
error text,
|
|
3520
|
-
created_on timestamp with time zone NOT NULL DEFAULT now(),
|
|
3521
|
-
started_on timestamp with time zone,
|
|
3522
|
-
completed_on timestamp with time zone
|
|
3523
|
-
)
|
|
3524
|
-
`,
|
|
3525
|
-
`CREATE FUNCTION ${schema}.job_table_format(command text, table_name text)
|
|
3526
|
-
RETURNS text AS
|
|
3527
|
-
$$
|
|
3528
|
-
SELECT format(
|
|
3529
|
-
replace(
|
|
3530
|
-
replace(command, '.job', '.%1$I'),
|
|
3531
|
-
'job_i', '%1$s_i'
|
|
3532
|
-
),
|
|
3533
|
-
table_name
|
|
3534
|
-
);
|
|
3535
|
-
$$
|
|
3536
|
-
LANGUAGE sql IMMUTABLE;
|
|
3537
|
-
`,
|
|
3538
|
-
`
|
|
3539
|
-
CREATE OR REPLACE FUNCTION ${schema}.job_table_run_async(command_name text, version int, command text, tbl_name text DEFAULT NULL, queue_name text DEFAULT NULL)
|
|
3540
|
-
RETURNS VOID AS
|
|
3541
|
-
$$
|
|
3542
|
-
BEGIN
|
|
3543
|
-
IF queue_name IS NOT NULL THEN
|
|
3544
|
-
SELECT table_name INTO tbl_name FROM ${schema}.queue WHERE name = queue_name;
|
|
3545
|
-
END IF;
|
|
3743
|
+
IF options->>'policy' = 'short' THEN
|
|
3744
|
+
EXECUTE format('CREATE UNIQUE INDEX %1$s_i1 ON ${schema}.%1$I (name, COALESCE(singleton_key, '''')) WHERE state = ''created'' AND policy = ''short''', tablename);
|
|
3745
|
+
ELSIF options->>'policy' = 'singleton' THEN
|
|
3746
|
+
EXECUTE format('CREATE UNIQUE INDEX %1$s_i2 ON ${schema}.%1$I (name, COALESCE(singleton_key, '''')) WHERE state = ''active'' AND policy = ''singleton''', tablename);
|
|
3747
|
+
ELSIF options->>'policy' = 'stately' THEN
|
|
3748
|
+
EXECUTE format('CREATE UNIQUE INDEX %1$s_i3 ON ${schema}.%1$I (name, state, COALESCE(singleton_key, '''')) WHERE state <= ''active'' AND policy = ''stately''', tablename);
|
|
3749
|
+
ELSIF options->>'policy' = 'exclusive' THEN
|
|
3750
|
+
EXECUTE format('CREATE UNIQUE INDEX %1$s_i6 ON ${schema}.%1$I (name, COALESCE(singleton_key, '''')) WHERE state <= ''active'' AND policy = ''exclusive''', tablename);
|
|
3751
|
+
END IF;
|
|
3546
3752
|
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
|
|
3552
|
-
|
|
3553
|
-
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
|
|
3557
|
-
|
|
3558
|
-
|
|
3753
|
+
EXECUTE format('ALTER TABLE ${schema}.%I ADD CONSTRAINT cjc CHECK (name=%L)', tablename, queue_name);
|
|
3754
|
+
EXECUTE format('ALTER TABLE ${schema}.job ATTACH PARTITION ${schema}.%I FOR VALUES IN (%L)', tablename, queue_name);
|
|
3755
|
+
END;
|
|
3756
|
+
$$
|
|
3757
|
+
LANGUAGE plpgsql;
|
|
3758
|
+
`,
|
|
3759
|
+
27: (schema) => `
|
|
3760
|
+
CREATE OR REPLACE FUNCTION ${schema}.create_queue(queue_name text, options jsonb)
|
|
3761
|
+
RETURNS VOID AS
|
|
3762
|
+
$$
|
|
3763
|
+
DECLARE
|
|
3764
|
+
tablename varchar := CASE WHEN options->>'partition' = 'true'
|
|
3765
|
+
THEN 'j' || encode(sha224(queue_name::bytea), 'hex')
|
|
3766
|
+
ELSE 'job_common'
|
|
3767
|
+
END;
|
|
3768
|
+
queue_created_on timestamptz;
|
|
3769
|
+
BEGIN
|
|
3559
3770
|
|
|
3560
|
-
|
|
3561
|
-
|
|
3771
|
+
WITH q as (
|
|
3772
|
+
INSERT INTO ${schema}.queue (
|
|
3773
|
+
name,
|
|
3774
|
+
policy,
|
|
3775
|
+
retry_limit,
|
|
3776
|
+
retry_delay,
|
|
3777
|
+
retry_backoff,
|
|
3778
|
+
retry_delay_max,
|
|
3779
|
+
expire_seconds,
|
|
3780
|
+
retention_seconds,
|
|
3781
|
+
deletion_seconds,
|
|
3782
|
+
warning_queued,
|
|
3783
|
+
dead_letter,
|
|
3784
|
+
partition,
|
|
3785
|
+
table_name
|
|
3786
|
+
)
|
|
3787
|
+
VALUES (
|
|
3788
|
+
queue_name,
|
|
3789
|
+
options->>'policy',
|
|
3790
|
+
COALESCE((options->>'retryLimit')::int, 2),
|
|
3791
|
+
COALESCE((options->>'retryDelay')::int, 0),
|
|
3792
|
+
COALESCE((options->>'retryBackoff')::bool, false),
|
|
3793
|
+
(options->>'retryDelayMax')::int,
|
|
3794
|
+
COALESCE((options->>'expireInSeconds')::int, 900),
|
|
3795
|
+
COALESCE((options->>'retentionSeconds')::int, 1209600),
|
|
3796
|
+
COALESCE((options->>'deleteAfterSeconds')::int, 604800),
|
|
3797
|
+
COALESCE((options->>'warningQueueSize')::int, 0),
|
|
3798
|
+
options->>'deadLetter',
|
|
3799
|
+
COALESCE((options->>'partition')::bool, false),
|
|
3800
|
+
tablename
|
|
3801
|
+
)
|
|
3802
|
+
ON CONFLICT DO NOTHING
|
|
3803
|
+
RETURNING created_on
|
|
3804
|
+
)
|
|
3805
|
+
SELECT created_on into queue_created_on from q;
|
|
3806
|
+
|
|
3807
|
+
IF queue_created_on IS NULL OR options->>'partition' IS DISTINCT FROM 'true' THEN
|
|
3808
|
+
RETURN;
|
|
3809
|
+
END IF;
|
|
3810
|
+
|
|
3811
|
+
EXECUTE format('CREATE TABLE ${schema}.%I (LIKE ${schema}.job INCLUDING DEFAULTS)', tablename);
|
|
3812
|
+
|
|
3813
|
+
EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD PRIMARY KEY (name, id)$cmd$, tablename);
|
|
3814
|
+
EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD CONSTRAINT q_fkey FOREIGN KEY (name) REFERENCES ${schema}.queue (name) ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED$cmd$, tablename);
|
|
3815
|
+
EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD CONSTRAINT dlq_fkey FOREIGN KEY (dead_letter) REFERENCES ${schema}.queue (name) ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED$cmd$, tablename);
|
|
3816
|
+
|
|
3817
|
+
EXECUTE ${schema}.job_table_format($cmd$CREATE INDEX job_i5 ON ${schema}.job (name, start_after) INCLUDE (priority, created_on, id) WHERE state < 'active'$cmd$, tablename);
|
|
3818
|
+
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i4 ON ${schema}.job (name, singleton_on, COALESCE(singleton_key, '')) WHERE state <> 'cancelled' AND singleton_on IS NOT NULL$cmd$, tablename);
|
|
3819
|
+
EXECUTE ${schema}.job_table_format($cmd$CREATE INDEX job_i7 ON ${schema}.job (name, group_id) WHERE state = 'active' AND group_id IS NOT NULL$cmd$, tablename);
|
|
3820
|
+
|
|
3821
|
+
IF options->>'policy' = 'short' THEN
|
|
3822
|
+
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i1 ON ${schema}.job (name, COALESCE(singleton_key, '')) WHERE state = 'created' AND policy = 'short'$cmd$, tablename);
|
|
3823
|
+
ELSIF options->>'policy' = 'singleton' THEN
|
|
3824
|
+
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i2 ON ${schema}.job (name, COALESCE(singleton_key, '')) WHERE state = 'active' AND policy = 'singleton'$cmd$, tablename);
|
|
3825
|
+
ELSIF options->>'policy' = 'stately' THEN
|
|
3826
|
+
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i3 ON ${schema}.job (name, state, COALESCE(singleton_key, '')) WHERE state <= 'active' AND policy = 'stately'$cmd$, tablename);
|
|
3827
|
+
ELSIF options->>'policy' = 'exclusive' THEN
|
|
3828
|
+
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i6 ON ${schema}.job (name, COALESCE(singleton_key, '')) WHERE state <= 'active' AND policy = 'exclusive'$cmd$, tablename);
|
|
3829
|
+
END IF;
|
|
3830
|
+
|
|
3831
|
+
EXECUTE format('ALTER TABLE ${schema}.%I ADD CONSTRAINT cjc CHECK (name=%L)', tablename, queue_name);
|
|
3832
|
+
EXECUTE format('ALTER TABLE ${schema}.job ATTACH PARTITION ${schema}.%I FOR VALUES IN (%L)', tablename, queue_name);
|
|
3833
|
+
END;
|
|
3834
|
+
$$
|
|
3835
|
+
LANGUAGE plpgsql;
|
|
3836
|
+
`,
|
|
3837
|
+
28: (schema) => `
|
|
3838
|
+
CREATE OR REPLACE FUNCTION ${schema}.create_queue(queue_name text, options jsonb)
|
|
3839
|
+
RETURNS VOID AS
|
|
3840
|
+
$$
|
|
3841
|
+
DECLARE
|
|
3842
|
+
tablename varchar := CASE WHEN options->>'partition' = 'true'
|
|
3843
|
+
THEN 'j' || encode(sha224(queue_name::bytea), 'hex')
|
|
3844
|
+
ELSE 'job_common'
|
|
3845
|
+
END;
|
|
3846
|
+
queue_created_on timestamptz;
|
|
3847
|
+
BEGIN
|
|
3848
|
+
|
|
3849
|
+
WITH q as (
|
|
3850
|
+
INSERT INTO ${schema}.queue (
|
|
3851
|
+
name,
|
|
3852
|
+
policy,
|
|
3853
|
+
retry_limit,
|
|
3854
|
+
retry_delay,
|
|
3855
|
+
retry_backoff,
|
|
3856
|
+
retry_delay_max,
|
|
3857
|
+
expire_seconds,
|
|
3858
|
+
retention_seconds,
|
|
3859
|
+
deletion_seconds,
|
|
3860
|
+
warning_queued,
|
|
3861
|
+
dead_letter,
|
|
3862
|
+
partition,
|
|
3863
|
+
table_name
|
|
3864
|
+
)
|
|
3865
|
+
VALUES (
|
|
3866
|
+
queue_name,
|
|
3867
|
+
options->>'policy',
|
|
3868
|
+
COALESCE((options->>'retryLimit')::int, 2),
|
|
3869
|
+
COALESCE((options->>'retryDelay')::int, 0),
|
|
3870
|
+
COALESCE((options->>'retryBackoff')::bool, false),
|
|
3871
|
+
(options->>'retryDelayMax')::int,
|
|
3872
|
+
COALESCE((options->>'expireInSeconds')::int, 900),
|
|
3873
|
+
COALESCE((options->>'retentionSeconds')::int, 1209600),
|
|
3874
|
+
COALESCE((options->>'deleteAfterSeconds')::int, 604800),
|
|
3875
|
+
COALESCE((options->>'warningQueueSize')::int, 0),
|
|
3876
|
+
options->>'deadLetter',
|
|
3877
|
+
COALESCE((options->>'partition')::bool, false),
|
|
3878
|
+
tablename
|
|
3879
|
+
)
|
|
3880
|
+
ON CONFLICT DO NOTHING
|
|
3881
|
+
RETURNING created_on
|
|
3882
|
+
)
|
|
3883
|
+
SELECT created_on into queue_created_on from q;
|
|
3884
|
+
|
|
3885
|
+
IF queue_created_on IS NULL OR options->>'partition' IS DISTINCT FROM 'true' THEN
|
|
3886
|
+
RETURN;
|
|
3887
|
+
END IF;
|
|
3888
|
+
|
|
3889
|
+
EXECUTE format('CREATE TABLE ${schema}.%I (LIKE ${schema}.job INCLUDING DEFAULTS)', tablename);
|
|
3890
|
+
|
|
3891
|
+
EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD PRIMARY KEY (name, id)$cmd$, tablename);
|
|
3892
|
+
EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD CONSTRAINT q_fkey FOREIGN KEY (name) REFERENCES ${schema}.queue (name) ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED$cmd$, tablename);
|
|
3893
|
+
EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD CONSTRAINT dlq_fkey FOREIGN KEY (dead_letter) REFERENCES ${schema}.queue (name) ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED$cmd$, tablename);
|
|
3894
|
+
|
|
3895
|
+
EXECUTE ${schema}.job_table_format($cmd$CREATE INDEX job_i5 ON ${schema}.job (name, start_after) INCLUDE (priority, created_on, id) WHERE state < 'active'$cmd$, tablename);
|
|
3896
|
+
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i4 ON ${schema}.job (name, singleton_on, COALESCE(singleton_key, '')) WHERE state <> 'cancelled' AND singleton_on IS NOT NULL$cmd$, tablename);
|
|
3897
|
+
EXECUTE ${schema}.job_table_format($cmd$CREATE INDEX job_i7 ON ${schema}.job (name, group_id) WHERE state = 'active' AND group_id IS NOT NULL$cmd$, tablename);
|
|
3898
|
+
|
|
3899
|
+
IF options->>'policy' = 'short' THEN
|
|
3900
|
+
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i1 ON ${schema}.job (name, COALESCE(singleton_key, '')) WHERE state = 'created' AND policy = 'short'$cmd$, tablename);
|
|
3901
|
+
ELSIF options->>'policy' = 'singleton' THEN
|
|
3902
|
+
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i2 ON ${schema}.job (name, COALESCE(singleton_key, '')) WHERE state = 'active' AND policy = 'singleton'$cmd$, tablename);
|
|
3903
|
+
ELSIF options->>'policy' = 'stately' THEN
|
|
3904
|
+
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i3 ON ${schema}.job (name, state, COALESCE(singleton_key, '')) WHERE state <= 'active' AND policy = 'stately'$cmd$, tablename);
|
|
3905
|
+
ELSIF options->>'policy' = 'exclusive' THEN
|
|
3906
|
+
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i6 ON ${schema}.job (name, COALESCE(singleton_key, '')) WHERE state <= 'active' AND policy = 'exclusive'$cmd$, tablename);
|
|
3907
|
+
ELSIF options->>'policy' = 'key_strict_fifo' THEN
|
|
3908
|
+
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i8 ON ${schema}.job (name, singleton_key) WHERE state IN ('active', 'retry', 'failed') AND policy = 'key_strict_fifo'$cmd$, tablename);
|
|
3909
|
+
EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD CONSTRAINT job_key_strict_fifo_singleton_key_check CHECK (NOT (policy = 'key_strict_fifo' AND singleton_key IS NULL))$cmd$, tablename);
|
|
3910
|
+
END IF;
|
|
3911
|
+
|
|
3912
|
+
EXECUTE format('ALTER TABLE ${schema}.%I ADD CONSTRAINT cjc CHECK (name=%L)', tablename, queue_name);
|
|
3913
|
+
EXECUTE format('ALTER TABLE ${schema}.job ATTACH PARTITION ${schema}.%I FOR VALUES IN (%L)', tablename, queue_name);
|
|
3914
|
+
END;
|
|
3915
|
+
$$
|
|
3916
|
+
LANGUAGE plpgsql;
|
|
3917
|
+
`,
|
|
3918
|
+
30: (schema) => `
|
|
3919
|
+
CREATE OR REPLACE FUNCTION ${schema}.create_queue(queue_name text, options jsonb)
|
|
3920
|
+
RETURNS VOID AS
|
|
3921
|
+
$$
|
|
3922
|
+
DECLARE
|
|
3923
|
+
tablename varchar := CASE WHEN options->>'partition' = 'true'
|
|
3924
|
+
THEN 'j' || encode(sha224(queue_name::bytea), 'hex')
|
|
3925
|
+
ELSE 'job_common'
|
|
3926
|
+
END;
|
|
3927
|
+
queue_created_on timestamptz;
|
|
3928
|
+
BEGIN
|
|
3929
|
+
|
|
3930
|
+
WITH q as (
|
|
3931
|
+
INSERT INTO ${schema}.queue (
|
|
3932
|
+
name,
|
|
3933
|
+
policy,
|
|
3934
|
+
retry_limit,
|
|
3935
|
+
retry_delay,
|
|
3936
|
+
retry_backoff,
|
|
3937
|
+
retry_delay_max,
|
|
3938
|
+
expire_seconds,
|
|
3939
|
+
retention_seconds,
|
|
3940
|
+
deletion_seconds,
|
|
3941
|
+
warning_queued,
|
|
3942
|
+
dead_letter,
|
|
3943
|
+
partition,
|
|
3944
|
+
table_name,
|
|
3945
|
+
heartbeat_seconds
|
|
3946
|
+
)
|
|
3947
|
+
VALUES (
|
|
3948
|
+
queue_name,
|
|
3949
|
+
options->>'policy',
|
|
3950
|
+
COALESCE((options->>'retryLimit')::int, 2),
|
|
3951
|
+
COALESCE((options->>'retryDelay')::int, 0),
|
|
3952
|
+
COALESCE((options->>'retryBackoff')::bool, false),
|
|
3953
|
+
(options->>'retryDelayMax')::int,
|
|
3954
|
+
COALESCE((options->>'expireInSeconds')::int, 900),
|
|
3955
|
+
COALESCE((options->>'retentionSeconds')::int, 1209600),
|
|
3956
|
+
COALESCE((options->>'deleteAfterSeconds')::int, 604800),
|
|
3957
|
+
COALESCE((options->>'warningQueueSize')::int, 0),
|
|
3958
|
+
options->>'deadLetter',
|
|
3959
|
+
COALESCE((options->>'partition')::bool, false),
|
|
3960
|
+
tablename,
|
|
3961
|
+
(options->>'heartbeatSeconds')::int
|
|
3962
|
+
)
|
|
3963
|
+
ON CONFLICT DO NOTHING
|
|
3964
|
+
RETURNING created_on
|
|
3965
|
+
)
|
|
3966
|
+
SELECT created_on into queue_created_on from q;
|
|
3967
|
+
|
|
3968
|
+
IF queue_created_on IS NULL OR options->>'partition' IS DISTINCT FROM 'true' THEN
|
|
3969
|
+
RETURN;
|
|
3970
|
+
END IF;
|
|
3971
|
+
|
|
3972
|
+
EXECUTE format('CREATE TABLE ${schema}.%I (LIKE ${schema}.job INCLUDING DEFAULTS)', tablename);
|
|
3973
|
+
|
|
3974
|
+
EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD PRIMARY KEY (name, id)$cmd$, tablename);
|
|
3975
|
+
EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD CONSTRAINT q_fkey FOREIGN KEY (name) REFERENCES ${schema}.queue (name) ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED$cmd$, tablename);
|
|
3976
|
+
EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD CONSTRAINT dlq_fkey FOREIGN KEY (dead_letter) REFERENCES ${schema}.queue (name) ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED$cmd$, tablename);
|
|
3977
|
+
|
|
3978
|
+
EXECUTE ${schema}.job_table_format($cmd$CREATE INDEX job_i5 ON ${schema}.job (name, start_after) INCLUDE (priority, created_on, id) WHERE state < 'active'$cmd$, tablename);
|
|
3979
|
+
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i4 ON ${schema}.job (name, singleton_on, COALESCE(singleton_key, '')) WHERE state <> 'cancelled' AND singleton_on IS NOT NULL$cmd$, tablename);
|
|
3980
|
+
EXECUTE ${schema}.job_table_format($cmd$CREATE INDEX job_i7 ON ${schema}.job (name, group_id) WHERE state = 'active' AND group_id IS NOT NULL$cmd$, tablename);
|
|
3981
|
+
|
|
3982
|
+
IF options->>'policy' = 'short' THEN
|
|
3983
|
+
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i1 ON ${schema}.job (name, COALESCE(singleton_key, '')) WHERE state = 'created' AND policy = 'short'$cmd$, tablename);
|
|
3984
|
+
ELSIF options->>'policy' = 'singleton' THEN
|
|
3985
|
+
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i2 ON ${schema}.job (name, COALESCE(singleton_key, '')) WHERE state = 'active' AND policy = 'singleton'$cmd$, tablename);
|
|
3986
|
+
ELSIF options->>'policy' = 'stately' THEN
|
|
3987
|
+
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i3 ON ${schema}.job (name, state, COALESCE(singleton_key, '')) WHERE state <= 'active' AND policy = 'stately'$cmd$, tablename);
|
|
3988
|
+
ELSIF options->>'policy' = 'exclusive' THEN
|
|
3989
|
+
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i6 ON ${schema}.job (name, COALESCE(singleton_key, '')) WHERE state <= 'active' AND policy = 'exclusive'$cmd$, tablename);
|
|
3990
|
+
ELSIF options->>'policy' = 'key_strict_fifo' THEN
|
|
3991
|
+
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i8 ON ${schema}.job (name, singleton_key) WHERE state IN ('active', 'retry', 'failed') AND policy = 'key_strict_fifo'$cmd$, tablename);
|
|
3992
|
+
EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD CONSTRAINT job_key_strict_fifo_singleton_key_check CHECK (NOT (policy = 'key_strict_fifo' AND singleton_key IS NULL))$cmd$, tablename);
|
|
3993
|
+
END IF;
|
|
3994
|
+
|
|
3995
|
+
EXECUTE format('ALTER TABLE ${schema}.%I ADD CONSTRAINT cjc CHECK (name=%L)', tablename, queue_name);
|
|
3996
|
+
EXECUTE format('ALTER TABLE ${schema}.job ATTACH PARTITION ${schema}.%I FOR VALUES IN (%L)', tablename, queue_name);
|
|
3997
|
+
END;
|
|
3998
|
+
$$
|
|
3999
|
+
LANGUAGE plpgsql;
|
|
4000
|
+
`,
|
|
4001
|
+
31: (schema) => `
|
|
4002
|
+
CREATE OR REPLACE FUNCTION ${schema}.create_queue(queue_name text, options jsonb)
|
|
4003
|
+
RETURNS VOID AS
|
|
4004
|
+
$$
|
|
4005
|
+
DECLARE
|
|
4006
|
+
tablename varchar := CASE WHEN options->>'partition' = 'true'
|
|
4007
|
+
THEN 'j' || encode(sha224(queue_name::bytea), 'hex')
|
|
4008
|
+
ELSE 'job_common'
|
|
4009
|
+
END;
|
|
4010
|
+
queue_created_on timestamptz;
|
|
4011
|
+
BEGIN
|
|
4012
|
+
|
|
4013
|
+
WITH q as (
|
|
4014
|
+
INSERT INTO ${schema}.queue (
|
|
4015
|
+
name,
|
|
4016
|
+
policy,
|
|
4017
|
+
retry_limit,
|
|
4018
|
+
retry_delay,
|
|
4019
|
+
retry_backoff,
|
|
4020
|
+
retry_delay_max,
|
|
4021
|
+
expire_seconds,
|
|
4022
|
+
retention_seconds,
|
|
4023
|
+
deletion_seconds,
|
|
4024
|
+
warning_queued,
|
|
4025
|
+
dead_letter,
|
|
4026
|
+
partition,
|
|
4027
|
+
table_name,
|
|
4028
|
+
heartbeat_seconds
|
|
4029
|
+
)
|
|
4030
|
+
VALUES (
|
|
4031
|
+
queue_name,
|
|
4032
|
+
options->>'policy',
|
|
4033
|
+
COALESCE((options->>'retryLimit')::int, 2),
|
|
4034
|
+
COALESCE((options->>'retryDelay')::int, 0),
|
|
4035
|
+
COALESCE((options->>'retryBackoff')::bool, false),
|
|
4036
|
+
(options->>'retryDelayMax')::int,
|
|
4037
|
+
COALESCE((options->>'expireInSeconds')::int, 900),
|
|
4038
|
+
COALESCE((options->>'retentionSeconds')::int, 1209600),
|
|
4039
|
+
COALESCE((options->>'deleteAfterSeconds')::int, 604800),
|
|
4040
|
+
COALESCE((options->>'warningQueueSize')::int, 0),
|
|
4041
|
+
options->>'deadLetter',
|
|
4042
|
+
COALESCE((options->>'partition')::bool, false),
|
|
4043
|
+
tablename,
|
|
4044
|
+
(options->>'heartbeatSeconds')::int
|
|
4045
|
+
)
|
|
4046
|
+
ON CONFLICT DO NOTHING
|
|
4047
|
+
RETURNING created_on
|
|
4048
|
+
)
|
|
4049
|
+
SELECT created_on into queue_created_on from q;
|
|
4050
|
+
|
|
4051
|
+
IF queue_created_on IS NULL OR options->>'partition' IS DISTINCT FROM 'true' THEN
|
|
4052
|
+
RETURN;
|
|
4053
|
+
END IF;
|
|
4054
|
+
|
|
4055
|
+
EXECUTE format('CREATE TABLE ${schema}.%I (LIKE ${schema}.job INCLUDING DEFAULTS)', tablename);
|
|
4056
|
+
|
|
4057
|
+
EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD PRIMARY KEY (name, id)$cmd$, tablename);
|
|
4058
|
+
EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD CONSTRAINT q_fkey FOREIGN KEY (name) REFERENCES ${schema}.queue (name) ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED$cmd$, tablename);
|
|
4059
|
+
EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD CONSTRAINT dlq_fkey FOREIGN KEY (dead_letter) REFERENCES ${schema}.queue (name) ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED$cmd$, tablename);
|
|
4060
|
+
|
|
4061
|
+
EXECUTE ${schema}.job_table_format($cmd$CREATE INDEX job_i5 ON ${schema}.job (name, start_after) INCLUDE (priority, created_on, id) WHERE state < 'active' AND NOT blocked$cmd$, tablename);
|
|
4062
|
+
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i4 ON ${schema}.job (name, singleton_on, COALESCE(singleton_key, '')) WHERE state <> 'cancelled' AND singleton_on IS NOT NULL$cmd$, tablename);
|
|
4063
|
+
EXECUTE ${schema}.job_table_format($cmd$CREATE INDEX job_i7 ON ${schema}.job (name, group_id) WHERE state = 'active' AND group_id IS NOT NULL$cmd$, tablename);
|
|
4064
|
+
|
|
4065
|
+
IF options->>'policy' = 'short' THEN
|
|
4066
|
+
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i1 ON ${schema}.job (name, COALESCE(singleton_key, '')) WHERE state = 'created' AND policy = 'short'$cmd$, tablename);
|
|
4067
|
+
ELSIF options->>'policy' = 'singleton' THEN
|
|
4068
|
+
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i2 ON ${schema}.job (name, COALESCE(singleton_key, '')) WHERE state = 'active' AND policy = 'singleton'$cmd$, tablename);
|
|
4069
|
+
ELSIF options->>'policy' = 'stately' THEN
|
|
4070
|
+
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i3 ON ${schema}.job (name, state, COALESCE(singleton_key, '')) WHERE state <= 'active' AND policy = 'stately'$cmd$, tablename);
|
|
4071
|
+
ELSIF options->>'policy' = 'exclusive' THEN
|
|
4072
|
+
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i6 ON ${schema}.job (name, COALESCE(singleton_key, '')) WHERE state <= 'active' AND policy = 'exclusive'$cmd$, tablename);
|
|
4073
|
+
ELSIF options->>'policy' = 'key_strict_fifo' THEN
|
|
4074
|
+
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i8 ON ${schema}.job (name, singleton_key) WHERE state IN ('active', 'retry', 'failed') AND policy = 'key_strict_fifo'$cmd$, tablename);
|
|
4075
|
+
EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD CONSTRAINT job_key_strict_fifo_singleton_key_check CHECK (NOT (policy = 'key_strict_fifo' AND singleton_key IS NULL))$cmd$, tablename);
|
|
4076
|
+
END IF;
|
|
4077
|
+
|
|
4078
|
+
EXECUTE format('ALTER TABLE ${schema}.%I ADD CONSTRAINT cjc CHECK (name=%L)', tablename, queue_name);
|
|
4079
|
+
EXECUTE format('ALTER TABLE ${schema}.job ATTACH PARTITION ${schema}.%I FOR VALUES IN (%L)', tablename, queue_name);
|
|
4080
|
+
END;
|
|
4081
|
+
$$
|
|
4082
|
+
LANGUAGE plpgsql;
|
|
4083
|
+
`,
|
|
4084
|
+
32: (schema) => `
|
|
4085
|
+
CREATE OR REPLACE FUNCTION ${schema}.create_queue(queue_name text, options jsonb)
|
|
4086
|
+
RETURNS VOID AS
|
|
4087
|
+
$$
|
|
4088
|
+
DECLARE
|
|
4089
|
+
tablename varchar := CASE WHEN options->>'partition' = 'true'
|
|
4090
|
+
THEN 'j' || encode(sha224(queue_name::bytea), 'hex')
|
|
4091
|
+
ELSE 'job_common'
|
|
4092
|
+
END;
|
|
4093
|
+
queue_created_on timestamptz;
|
|
4094
|
+
BEGIN
|
|
4095
|
+
|
|
4096
|
+
WITH q as (
|
|
4097
|
+
INSERT INTO ${schema}.queue (
|
|
4098
|
+
name,
|
|
4099
|
+
policy,
|
|
4100
|
+
retry_limit,
|
|
4101
|
+
retry_delay,
|
|
4102
|
+
retry_backoff,
|
|
4103
|
+
retry_delay_max,
|
|
4104
|
+
expire_seconds,
|
|
4105
|
+
retention_seconds,
|
|
4106
|
+
deletion_seconds,
|
|
4107
|
+
warning_queued,
|
|
4108
|
+
dead_letter,
|
|
4109
|
+
partition,
|
|
4110
|
+
table_name,
|
|
4111
|
+
heartbeat_seconds,
|
|
4112
|
+
notify
|
|
4113
|
+
)
|
|
4114
|
+
VALUES (
|
|
4115
|
+
queue_name,
|
|
4116
|
+
options->>'policy',
|
|
4117
|
+
COALESCE((options->>'retryLimit')::int, 2),
|
|
4118
|
+
COALESCE((options->>'retryDelay')::int, 0),
|
|
4119
|
+
COALESCE((options->>'retryBackoff')::bool, false),
|
|
4120
|
+
(options->>'retryDelayMax')::int,
|
|
4121
|
+
COALESCE((options->>'expireInSeconds')::int, 900),
|
|
4122
|
+
COALESCE((options->>'retentionSeconds')::int, 1209600),
|
|
4123
|
+
COALESCE((options->>'deleteAfterSeconds')::int, 604800),
|
|
4124
|
+
COALESCE((options->>'warningQueueSize')::int, 0),
|
|
4125
|
+
options->>'deadLetter',
|
|
4126
|
+
COALESCE((options->>'partition')::bool, false),
|
|
4127
|
+
tablename,
|
|
4128
|
+
(options->>'heartbeatSeconds')::int,
|
|
4129
|
+
COALESCE((options->>'notify')::bool, false)
|
|
4130
|
+
)
|
|
4131
|
+
ON CONFLICT DO NOTHING
|
|
4132
|
+
RETURNING created_on
|
|
4133
|
+
)
|
|
4134
|
+
SELECT created_on into queue_created_on from q;
|
|
4135
|
+
|
|
4136
|
+
IF queue_created_on IS NULL OR options->>'partition' IS DISTINCT FROM 'true' THEN
|
|
4137
|
+
RETURN;
|
|
4138
|
+
END IF;
|
|
4139
|
+
|
|
4140
|
+
EXECUTE format('CREATE TABLE ${schema}.%I (LIKE ${schema}.job INCLUDING DEFAULTS)', tablename);
|
|
4141
|
+
|
|
4142
|
+
EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD PRIMARY KEY (name, id)$cmd$, tablename);
|
|
4143
|
+
EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD CONSTRAINT q_fkey FOREIGN KEY (name) REFERENCES ${schema}.queue (name) ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED$cmd$, tablename);
|
|
4144
|
+
EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD CONSTRAINT dlq_fkey FOREIGN KEY (dead_letter) REFERENCES ${schema}.queue (name) ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED$cmd$, tablename);
|
|
4145
|
+
|
|
4146
|
+
EXECUTE ${schema}.job_table_format($cmd$CREATE INDEX job_i5 ON ${schema}.job (name, start_after) INCLUDE (priority, created_on, id) WHERE state < 'active' AND NOT blocked$cmd$, tablename);
|
|
4147
|
+
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i4 ON ${schema}.job (name, singleton_on, COALESCE(singleton_key, '')) WHERE state <> 'cancelled' AND singleton_on IS NOT NULL$cmd$, tablename);
|
|
4148
|
+
EXECUTE ${schema}.job_table_format($cmd$CREATE INDEX job_i7 ON ${schema}.job (name, group_id) WHERE state = 'active' AND group_id IS NOT NULL$cmd$, tablename);
|
|
4149
|
+
|
|
4150
|
+
IF options->>'policy' = 'short' THEN
|
|
4151
|
+
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i1 ON ${schema}.job (name, COALESCE(singleton_key, '')) WHERE state = 'created' AND policy = 'short'$cmd$, tablename);
|
|
4152
|
+
ELSIF options->>'policy' = 'singleton' THEN
|
|
4153
|
+
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i2 ON ${schema}.job (name, COALESCE(singleton_key, '')) WHERE state = 'active' AND policy = 'singleton'$cmd$, tablename);
|
|
4154
|
+
ELSIF options->>'policy' = 'stately' THEN
|
|
4155
|
+
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i3 ON ${schema}.job (name, state, COALESCE(singleton_key, '')) WHERE state <= 'active' AND policy = 'stately'$cmd$, tablename);
|
|
4156
|
+
ELSIF options->>'policy' = 'exclusive' THEN
|
|
4157
|
+
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i6 ON ${schema}.job (name, COALESCE(singleton_key, '')) WHERE state <= 'active' AND policy = 'exclusive'$cmd$, tablename);
|
|
4158
|
+
ELSIF options->>'policy' = 'key_strict_fifo' THEN
|
|
4159
|
+
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i8 ON ${schema}.job (name, singleton_key) WHERE state IN ('active', 'retry', 'failed') AND policy = 'key_strict_fifo'$cmd$, tablename);
|
|
4160
|
+
EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD CONSTRAINT job_key_strict_fifo_singleton_key_check CHECK (NOT (policy = 'key_strict_fifo' AND singleton_key IS NULL))$cmd$, tablename);
|
|
4161
|
+
END IF;
|
|
4162
|
+
|
|
4163
|
+
EXECUTE format('ALTER TABLE ${schema}.%I ADD CONSTRAINT cjc CHECK (name=%L)', tablename, queue_name);
|
|
4164
|
+
EXECUTE format('ALTER TABLE ${schema}.job ATTACH PARTITION ${schema}.%I FOR VALUES IN (%L)', tablename, queue_name);
|
|
4165
|
+
END;
|
|
4166
|
+
$$
|
|
4167
|
+
LANGUAGE plpgsql;
|
|
4168
|
+
`,
|
|
4169
|
+
33: (schema) => `
|
|
4170
|
+
CREATE OR REPLACE FUNCTION ${schema}.create_queue(queue_name text, options jsonb)
|
|
4171
|
+
RETURNS VOID AS
|
|
4172
|
+
$$
|
|
4173
|
+
DECLARE
|
|
4174
|
+
tablename varchar := CASE WHEN options->>'partition' = 'true'
|
|
4175
|
+
THEN 'j' || encode(sha224(queue_name::bytea), 'hex')
|
|
4176
|
+
ELSE 'job_common'
|
|
4177
|
+
END;
|
|
4178
|
+
queue_created_on timestamptz;
|
|
4179
|
+
BEGIN
|
|
4180
|
+
|
|
4181
|
+
WITH q as (
|
|
4182
|
+
INSERT INTO ${schema}.queue (
|
|
4183
|
+
name,
|
|
4184
|
+
policy,
|
|
4185
|
+
retry_limit,
|
|
4186
|
+
retry_delay,
|
|
4187
|
+
retry_backoff,
|
|
4188
|
+
retry_delay_max,
|
|
4189
|
+
expire_seconds,
|
|
4190
|
+
retention_seconds,
|
|
4191
|
+
deletion_seconds,
|
|
4192
|
+
warning_queued,
|
|
4193
|
+
dead_letter,
|
|
4194
|
+
partition,
|
|
4195
|
+
table_name,
|
|
4196
|
+
heartbeat_seconds,
|
|
4197
|
+
notify
|
|
4198
|
+
)
|
|
4199
|
+
VALUES (
|
|
4200
|
+
queue_name,
|
|
4201
|
+
options->>'policy',
|
|
4202
|
+
COALESCE((options->>'retryLimit')::int, 2),
|
|
4203
|
+
COALESCE((options->>'retryDelay')::int, 0),
|
|
4204
|
+
COALESCE((options->>'retryBackoff')::bool, false),
|
|
4205
|
+
(options->>'retryDelayMax')::int,
|
|
4206
|
+
COALESCE((options->>'expireInSeconds')::int, 900),
|
|
4207
|
+
COALESCE((options->>'retentionSeconds')::int, 1209600),
|
|
4208
|
+
COALESCE((options->>'deleteAfterSeconds')::int, 604800),
|
|
4209
|
+
COALESCE((options->>'warningQueueSize')::int, 0),
|
|
4210
|
+
options->>'deadLetter',
|
|
4211
|
+
COALESCE((options->>'partition')::bool, false),
|
|
4212
|
+
tablename,
|
|
4213
|
+
(options->>'heartbeatSeconds')::int,
|
|
4214
|
+
COALESCE((options->>'notify')::bool, false)
|
|
4215
|
+
)
|
|
4216
|
+
ON CONFLICT DO NOTHING
|
|
4217
|
+
RETURNING created_on
|
|
4218
|
+
)
|
|
4219
|
+
SELECT created_on into queue_created_on from q;
|
|
4220
|
+
|
|
4221
|
+
IF queue_created_on IS NULL OR options->>'partition' IS DISTINCT FROM 'true' THEN
|
|
4222
|
+
RETURN;
|
|
4223
|
+
END IF;
|
|
4224
|
+
|
|
4225
|
+
EXECUTE format('CREATE TABLE ${schema}.%I (LIKE ${schema}.job INCLUDING DEFAULTS)', tablename);
|
|
4226
|
+
|
|
4227
|
+
EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD PRIMARY KEY (name, id)$cmd$, tablename);
|
|
4228
|
+
EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD CONSTRAINT q_fkey FOREIGN KEY (name) REFERENCES ${schema}.queue (name) ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED$cmd$, tablename);
|
|
4229
|
+
EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD CONSTRAINT dlq_fkey FOREIGN KEY (dead_letter) REFERENCES ${schema}.queue (name) ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED$cmd$, tablename);
|
|
4230
|
+
|
|
4231
|
+
EXECUTE ${schema}.job_table_format($cmd$CREATE INDEX job_i5 ON ${schema}.job (name, start_after) WHERE state < 'active' AND NOT blocked$cmd$, tablename);
|
|
4232
|
+
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i4 ON ${schema}.job (name, singleton_on, COALESCE(singleton_key, '')) WHERE state <> 'cancelled' AND singleton_on IS NOT NULL$cmd$, tablename);
|
|
4233
|
+
EXECUTE ${schema}.job_table_format($cmd$CREATE INDEX job_i7 ON ${schema}.job (name, group_id) WHERE state = 'active' AND group_id IS NOT NULL$cmd$, tablename);
|
|
4234
|
+
EXECUTE ${schema}.job_table_format($cmd$CREATE INDEX job_i9 ON ${schema}.job (name, id) WHERE blocking AND state = 'completed'$cmd$, tablename);
|
|
4235
|
+
|
|
4236
|
+
IF options->>'policy' = 'short' THEN
|
|
4237
|
+
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i1 ON ${schema}.job (name, COALESCE(singleton_key, '')) WHERE state = 'created' AND policy = 'short'$cmd$, tablename);
|
|
4238
|
+
ELSIF options->>'policy' = 'singleton' THEN
|
|
4239
|
+
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i2 ON ${schema}.job (name, COALESCE(singleton_key, '')) WHERE state = 'active' AND policy = 'singleton'$cmd$, tablename);
|
|
4240
|
+
ELSIF options->>'policy' = 'stately' THEN
|
|
4241
|
+
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i3 ON ${schema}.job (name, state, COALESCE(singleton_key, '')) WHERE state <= 'active' AND policy = 'stately'$cmd$, tablename);
|
|
4242
|
+
ELSIF options->>'policy' = 'exclusive' THEN
|
|
4243
|
+
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i6 ON ${schema}.job (name, COALESCE(singleton_key, '')) WHERE state <= 'active' AND policy = 'exclusive'$cmd$, tablename);
|
|
4244
|
+
ELSIF options->>'policy' = 'key_strict_fifo' THEN
|
|
4245
|
+
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i8 ON ${schema}.job (name, singleton_key) WHERE state IN ('active', 'retry', 'failed') AND policy = 'key_strict_fifo'$cmd$, tablename);
|
|
4246
|
+
EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD CONSTRAINT job_key_strict_fifo_singleton_key_check CHECK (NOT (policy = 'key_strict_fifo' AND singleton_key IS NULL))$cmd$, tablename);
|
|
4247
|
+
END IF;
|
|
4248
|
+
|
|
4249
|
+
EXECUTE format('ALTER TABLE ${schema}.%I ADD CONSTRAINT cjc CHECK (name=%L)', tablename, queue_name);
|
|
4250
|
+
EXECUTE format('ALTER TABLE ${schema}.job ATTACH PARTITION ${schema}.%I FOR VALUES IN (%L)', tablename, queue_name);
|
|
4251
|
+
END;
|
|
4252
|
+
$$
|
|
4253
|
+
LANGUAGE plpgsql;
|
|
4254
|
+
`
|
|
4255
|
+
};
|
|
4256
|
+
function getAll(schema) {
|
|
4257
|
+
return [
|
|
4258
|
+
{
|
|
4259
|
+
release: "11.1.0",
|
|
4260
|
+
version: 26,
|
|
4261
|
+
previous: 25,
|
|
4262
|
+
install: [createQueueFn[26](schema), `CREATE UNIQUE INDEX job_i6 ON ${schema}.job_common (name, COALESCE(singleton_key, '')) WHERE state <= 'active' AND policy = 'exclusive'`],
|
|
4263
|
+
uninstall: [`DROP INDEX ${schema}.job_i6`]
|
|
4264
|
+
},
|
|
4265
|
+
{
|
|
4266
|
+
release: "12.6.0",
|
|
4267
|
+
version: 27,
|
|
4268
|
+
previous: 26,
|
|
4269
|
+
install: [
|
|
4270
|
+
`ALTER TABLE ${schema}.version ADD COLUMN IF NOT EXISTS bam_on timestamp with time zone`,
|
|
4271
|
+
`
|
|
4272
|
+
CREATE TABLE IF NOT EXISTS ${schema}.bam (
|
|
4273
|
+
id uuid PRIMARY KEY default gen_random_uuid(),
|
|
4274
|
+
name text NOT NULL,
|
|
4275
|
+
version int NOT NULL,
|
|
4276
|
+
status text NOT NULL DEFAULT 'pending',
|
|
4277
|
+
queue text,
|
|
4278
|
+
table_name text NOT NULL,
|
|
4279
|
+
command text NOT NULL,
|
|
4280
|
+
error text,
|
|
4281
|
+
created_on timestamp with time zone NOT NULL DEFAULT now(),
|
|
4282
|
+
started_on timestamp with time zone,
|
|
4283
|
+
completed_on timestamp with time zone
|
|
4284
|
+
)
|
|
4285
|
+
`,
|
|
4286
|
+
`CREATE FUNCTION ${schema}.job_table_format(command text, table_name text)
|
|
4287
|
+
RETURNS text AS
|
|
4288
|
+
$$
|
|
4289
|
+
SELECT format(
|
|
4290
|
+
replace(
|
|
4291
|
+
replace(command, '.job', '.%1$I'),
|
|
4292
|
+
'job_i', '%1$s_i'
|
|
4293
|
+
),
|
|
4294
|
+
table_name
|
|
4295
|
+
);
|
|
4296
|
+
$$
|
|
4297
|
+
LANGUAGE sql IMMUTABLE;
|
|
4298
|
+
`,
|
|
4299
|
+
`
|
|
4300
|
+
CREATE OR REPLACE FUNCTION ${schema}.job_table_run_async(command_name text, version int, command text, tbl_name text DEFAULT NULL, queue_name text DEFAULT NULL)
|
|
4301
|
+
RETURNS VOID AS
|
|
4302
|
+
$$
|
|
4303
|
+
BEGIN
|
|
4304
|
+
IF queue_name IS NOT NULL THEN
|
|
4305
|
+
SELECT table_name INTO tbl_name FROM ${schema}.queue WHERE name = queue_name;
|
|
4306
|
+
END IF;
|
|
4307
|
+
|
|
4308
|
+
IF tbl_name IS NOT NULL THEN
|
|
4309
|
+
INSERT INTO ${schema}.bam (name, version, status, queue, table_name, command)
|
|
4310
|
+
VALUES (
|
|
4311
|
+
command_name,
|
|
4312
|
+
version,
|
|
4313
|
+
'pending',
|
|
4314
|
+
queue_name,
|
|
4315
|
+
tbl_name,
|
|
4316
|
+
${schema}.job_table_format(command, tbl_name)
|
|
4317
|
+
);
|
|
4318
|
+
RETURN;
|
|
4319
|
+
END IF;
|
|
4320
|
+
|
|
4321
|
+
INSERT INTO ${schema}.bam (name, version, status, queue, table_name, command)
|
|
4322
|
+
SELECT
|
|
3562
4323
|
command_name,
|
|
3563
4324
|
version,
|
|
3564
4325
|
'pending',
|
|
@@ -3607,84 +4368,7 @@ function getAll(schema) {
|
|
|
3607
4368
|
`,
|
|
3608
4369
|
`ALTER TABLE ${schema}.job ADD COLUMN IF NOT EXISTS group_id text`,
|
|
3609
4370
|
`ALTER TABLE ${schema}.job ADD COLUMN IF NOT EXISTS group_tier text`,
|
|
3610
|
-
|
|
3611
|
-
CREATE OR REPLACE FUNCTION ${schema}.create_queue(queue_name text, options jsonb)
|
|
3612
|
-
RETURNS VOID AS
|
|
3613
|
-
$$
|
|
3614
|
-
DECLARE
|
|
3615
|
-
tablename varchar := CASE WHEN options->>'partition' = 'true'
|
|
3616
|
-
THEN 'j' || encode(sha224(queue_name::bytea), 'hex')
|
|
3617
|
-
ELSE 'job_common'
|
|
3618
|
-
END;
|
|
3619
|
-
queue_created_on timestamptz;
|
|
3620
|
-
BEGIN
|
|
3621
|
-
|
|
3622
|
-
WITH q as (
|
|
3623
|
-
INSERT INTO ${schema}.queue (
|
|
3624
|
-
name,
|
|
3625
|
-
policy,
|
|
3626
|
-
retry_limit,
|
|
3627
|
-
retry_delay,
|
|
3628
|
-
retry_backoff,
|
|
3629
|
-
retry_delay_max,
|
|
3630
|
-
expire_seconds,
|
|
3631
|
-
retention_seconds,
|
|
3632
|
-
deletion_seconds,
|
|
3633
|
-
warning_queued,
|
|
3634
|
-
dead_letter,
|
|
3635
|
-
partition,
|
|
3636
|
-
table_name
|
|
3637
|
-
)
|
|
3638
|
-
VALUES (
|
|
3639
|
-
queue_name,
|
|
3640
|
-
options->>'policy',
|
|
3641
|
-
COALESCE((options->>'retryLimit')::int, 2),
|
|
3642
|
-
COALESCE((options->>'retryDelay')::int, 0),
|
|
3643
|
-
COALESCE((options->>'retryBackoff')::bool, false),
|
|
3644
|
-
(options->>'retryDelayMax')::int,
|
|
3645
|
-
COALESCE((options->>'expireInSeconds')::int, 900),
|
|
3646
|
-
COALESCE((options->>'retentionSeconds')::int, 1209600),
|
|
3647
|
-
COALESCE((options->>'deleteAfterSeconds')::int, 604800),
|
|
3648
|
-
COALESCE((options->>'warningQueueSize')::int, 0),
|
|
3649
|
-
options->>'deadLetter',
|
|
3650
|
-
COALESCE((options->>'partition')::bool, false),
|
|
3651
|
-
tablename
|
|
3652
|
-
)
|
|
3653
|
-
ON CONFLICT DO NOTHING
|
|
3654
|
-
RETURNING created_on
|
|
3655
|
-
)
|
|
3656
|
-
SELECT created_on into queue_created_on from q;
|
|
3657
|
-
|
|
3658
|
-
IF queue_created_on IS NULL OR options->>'partition' IS DISTINCT FROM 'true' THEN
|
|
3659
|
-
RETURN;
|
|
3660
|
-
END IF;
|
|
3661
|
-
|
|
3662
|
-
EXECUTE format('CREATE TABLE ${schema}.%I (LIKE ${schema}.job INCLUDING DEFAULTS)', tablename);
|
|
3663
|
-
|
|
3664
|
-
EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD PRIMARY KEY (name, id)$cmd$, tablename);
|
|
3665
|
-
EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD CONSTRAINT q_fkey FOREIGN KEY (name) REFERENCES ${schema}.queue (name) ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED$cmd$, tablename);
|
|
3666
|
-
EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD CONSTRAINT dlq_fkey FOREIGN KEY (dead_letter) REFERENCES ${schema}.queue (name) ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED$cmd$, tablename);
|
|
3667
|
-
|
|
3668
|
-
EXECUTE ${schema}.job_table_format($cmd$CREATE INDEX job_i5 ON ${schema}.job (name, start_after) INCLUDE (priority, created_on, id) WHERE state < 'active'$cmd$, tablename);
|
|
3669
|
-
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i4 ON ${schema}.job (name, singleton_on, COALESCE(singleton_key, '')) WHERE state <> 'cancelled' AND singleton_on IS NOT NULL$cmd$, tablename);
|
|
3670
|
-
EXECUTE ${schema}.job_table_format($cmd$CREATE INDEX job_i7 ON ${schema}.job (name, group_id) WHERE state = 'active' AND group_id IS NOT NULL$cmd$, tablename);
|
|
3671
|
-
|
|
3672
|
-
IF options->>'policy' = 'short' THEN
|
|
3673
|
-
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i1 ON ${schema}.job (name, COALESCE(singleton_key, '')) WHERE state = 'created' AND policy = 'short'$cmd$, tablename);
|
|
3674
|
-
ELSIF options->>'policy' = 'singleton' THEN
|
|
3675
|
-
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i2 ON ${schema}.job (name, COALESCE(singleton_key, '')) WHERE state = 'active' AND policy = 'singleton'$cmd$, tablename);
|
|
3676
|
-
ELSIF options->>'policy' = 'stately' THEN
|
|
3677
|
-
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i3 ON ${schema}.job (name, state, COALESCE(singleton_key, '')) WHERE state <= 'active' AND policy = 'stately'$cmd$, tablename);
|
|
3678
|
-
ELSIF options->>'policy' = 'exclusive' THEN
|
|
3679
|
-
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i6 ON ${schema}.job (name, COALESCE(singleton_key, '')) WHERE state <= 'active' AND policy = 'exclusive'$cmd$, tablename);
|
|
3680
|
-
END IF;
|
|
3681
|
-
|
|
3682
|
-
EXECUTE format('ALTER TABLE ${schema}.%I ADD CONSTRAINT cjc CHECK (name=%L)', tablename, queue_name);
|
|
3683
|
-
EXECUTE format('ALTER TABLE ${schema}.job ATTACH PARTITION ${schema}.%I FOR VALUES IN (%L)', tablename, queue_name);
|
|
3684
|
-
END;
|
|
3685
|
-
$$
|
|
3686
|
-
LANGUAGE plpgsql;
|
|
3687
|
-
`,
|
|
4371
|
+
createQueueFn[27](schema),
|
|
3688
4372
|
`ALTER INDEX IF EXISTS ${schema}.job_i1 RENAME TO job_common_i1`,
|
|
3689
4373
|
`ALTER INDEX IF EXISTS ${schema}.job_i2 RENAME TO job_common_i2`,
|
|
3690
4374
|
`ALTER INDEX IF EXISTS ${schema}.job_i3 RENAME TO job_common_i3`,
|
|
@@ -3708,83 +4392,7 @@ function getAll(schema) {
|
|
|
3708
4392
|
`ALTER INDEX ${schema}.job_common_i2 RENAME TO job_i2`,
|
|
3709
4393
|
`ALTER INDEX ${schema}.job_common_i1 RENAME TO job_i1`,
|
|
3710
4394
|
`SELECT ${schema}.job_table_run('DROP INDEX ${schema}.job_i7')`,
|
|
3711
|
-
|
|
3712
|
-
CREATE OR REPLACE FUNCTION ${schema}.create_queue(queue_name text, options jsonb)
|
|
3713
|
-
RETURNS VOID AS
|
|
3714
|
-
$$
|
|
3715
|
-
DECLARE
|
|
3716
|
-
tablename varchar := CASE WHEN options->>'partition' = 'true'
|
|
3717
|
-
THEN 'j' || encode(sha224(queue_name::bytea), 'hex')
|
|
3718
|
-
ELSE 'job_common'
|
|
3719
|
-
END;
|
|
3720
|
-
queue_created_on timestamptz;
|
|
3721
|
-
BEGIN
|
|
3722
|
-
|
|
3723
|
-
WITH q as (
|
|
3724
|
-
INSERT INTO ${schema}.queue (
|
|
3725
|
-
name,
|
|
3726
|
-
policy,
|
|
3727
|
-
retry_limit,
|
|
3728
|
-
retry_delay,
|
|
3729
|
-
retry_backoff,
|
|
3730
|
-
retry_delay_max,
|
|
3731
|
-
expire_seconds,
|
|
3732
|
-
retention_seconds,
|
|
3733
|
-
deletion_seconds,
|
|
3734
|
-
warning_queued,
|
|
3735
|
-
dead_letter,
|
|
3736
|
-
partition,
|
|
3737
|
-
table_name
|
|
3738
|
-
)
|
|
3739
|
-
VALUES (
|
|
3740
|
-
queue_name,
|
|
3741
|
-
options->>'policy',
|
|
3742
|
-
COALESCE((options->>'retryLimit')::int, 2),
|
|
3743
|
-
COALESCE((options->>'retryDelay')::int, 0),
|
|
3744
|
-
COALESCE((options->>'retryBackoff')::bool, false),
|
|
3745
|
-
(options->>'retryDelayMax')::int,
|
|
3746
|
-
COALESCE((options->>'expireInSeconds')::int, 900),
|
|
3747
|
-
COALESCE((options->>'retentionSeconds')::int, 1209600),
|
|
3748
|
-
COALESCE((options->>'deleteAfterSeconds')::int, 604800),
|
|
3749
|
-
COALESCE((options->>'warningQueueSize')::int, 0),
|
|
3750
|
-
options->>'deadLetter',
|
|
3751
|
-
COALESCE((options->>'partition')::bool, false),
|
|
3752
|
-
tablename
|
|
3753
|
-
)
|
|
3754
|
-
ON CONFLICT DO NOTHING
|
|
3755
|
-
RETURNING created_on
|
|
3756
|
-
)
|
|
3757
|
-
SELECT created_on into queue_created_on from q;
|
|
3758
|
-
|
|
3759
|
-
IF queue_created_on IS NULL OR options->>'partition' IS DISTINCT FROM 'true' THEN
|
|
3760
|
-
RETURN;
|
|
3761
|
-
END IF;
|
|
3762
|
-
|
|
3763
|
-
EXECUTE format('CREATE TABLE ${schema}.%I (LIKE ${schema}.job INCLUDING DEFAULTS)', tablename);
|
|
3764
|
-
|
|
3765
|
-
EXECUTE format('ALTER TABLE ${schema}.%1$I ADD PRIMARY KEY (name, id)', tablename);
|
|
3766
|
-
EXECUTE format('ALTER TABLE ${schema}.%1$I ADD CONSTRAINT q_fkey FOREIGN KEY (name) REFERENCES ${schema}.queue (name) ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED', tablename);
|
|
3767
|
-
EXECUTE format('ALTER TABLE ${schema}.%1$I ADD CONSTRAINT dlq_fkey FOREIGN KEY (dead_letter) REFERENCES ${schema}.queue (name) ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED', tablename);
|
|
3768
|
-
|
|
3769
|
-
EXECUTE format('CREATE INDEX %1$s_i5 ON ${schema}.%1$I (name, start_after) INCLUDE (priority, created_on, id) WHERE state < ''active''', tablename);
|
|
3770
|
-
EXECUTE format('CREATE UNIQUE INDEX %1$s_i4 ON ${schema}.%1$I (name, singleton_on, COALESCE(singleton_key, '''')) WHERE state <> ''cancelled'' AND singleton_on IS NOT NULL', tablename);
|
|
3771
|
-
|
|
3772
|
-
IF options->>'policy' = 'short' THEN
|
|
3773
|
-
EXECUTE format('CREATE UNIQUE INDEX %1$s_i1 ON ${schema}.%1$I (name, COALESCE(singleton_key, '''')) WHERE state = ''created'' AND policy = ''short''', tablename);
|
|
3774
|
-
ELSIF options->>'policy' = 'singleton' THEN
|
|
3775
|
-
EXECUTE format('CREATE UNIQUE INDEX %1$s_i2 ON ${schema}.%1$I (name, COALESCE(singleton_key, '''')) WHERE state = ''active'' AND policy = ''singleton''', tablename);
|
|
3776
|
-
ELSIF options->>'policy' = 'stately' THEN
|
|
3777
|
-
EXECUTE format('CREATE UNIQUE INDEX %1$s_i3 ON ${schema}.%1$I (name, state, COALESCE(singleton_key, '''')) WHERE state <= ''active'' AND policy = ''stately''', tablename);
|
|
3778
|
-
ELSIF options->>'policy' = 'exclusive' THEN
|
|
3779
|
-
EXECUTE format('CREATE UNIQUE INDEX %1$s_i6 ON ${schema}.%1$I (name, COALESCE(singleton_key, '''')) WHERE state <= ''active'' AND policy = ''exclusive''', tablename);
|
|
3780
|
-
END IF;
|
|
3781
|
-
|
|
3782
|
-
EXECUTE format('ALTER TABLE ${schema}.%I ADD CONSTRAINT cjc CHECK (name=%L)', tablename, queue_name);
|
|
3783
|
-
EXECUTE format('ALTER TABLE ${schema}.job ATTACH PARTITION ${schema}.%I FOR VALUES IN (%L)', tablename, queue_name);
|
|
3784
|
-
END;
|
|
3785
|
-
$$
|
|
3786
|
-
LANGUAGE plpgsql;
|
|
3787
|
-
`,
|
|
4395
|
+
createQueueFn[26](schema),
|
|
3788
4396
|
`DROP FUNCTION ${schema}.job_table_run(text, text, text)`,
|
|
3789
4397
|
`DROP FUNCTION ${schema}.job_table_run_async(text, int, text, text, text)`,
|
|
3790
4398
|
`DROP FUNCTION ${schema}.job_table_format(text, text)`,
|
|
@@ -3798,87 +4406,7 @@ function getAll(schema) {
|
|
|
3798
4406
|
release: "12.10.0",
|
|
3799
4407
|
version: 28,
|
|
3800
4408
|
previous: 27,
|
|
3801
|
-
install: [`SELECT ${schema}.job_table_run($cmd$ALTER TABLE ${schema}.job ADD CONSTRAINT job_key_strict_fifo_singleton_key_check CHECK (NOT (policy = 'key_strict_fifo' AND singleton_key IS NULL))$cmd$, 'job_common')`,
|
|
3802
|
-
CREATE OR REPLACE FUNCTION ${schema}.create_queue(queue_name text, options jsonb)
|
|
3803
|
-
RETURNS VOID AS
|
|
3804
|
-
$$
|
|
3805
|
-
DECLARE
|
|
3806
|
-
tablename varchar := CASE WHEN options->>'partition' = 'true'
|
|
3807
|
-
THEN 'j' || encode(sha224(queue_name::bytea), 'hex')
|
|
3808
|
-
ELSE 'job_common'
|
|
3809
|
-
END;
|
|
3810
|
-
queue_created_on timestamptz;
|
|
3811
|
-
BEGIN
|
|
3812
|
-
|
|
3813
|
-
WITH q as (
|
|
3814
|
-
INSERT INTO ${schema}.queue (
|
|
3815
|
-
name,
|
|
3816
|
-
policy,
|
|
3817
|
-
retry_limit,
|
|
3818
|
-
retry_delay,
|
|
3819
|
-
retry_backoff,
|
|
3820
|
-
retry_delay_max,
|
|
3821
|
-
expire_seconds,
|
|
3822
|
-
retention_seconds,
|
|
3823
|
-
deletion_seconds,
|
|
3824
|
-
warning_queued,
|
|
3825
|
-
dead_letter,
|
|
3826
|
-
partition,
|
|
3827
|
-
table_name
|
|
3828
|
-
)
|
|
3829
|
-
VALUES (
|
|
3830
|
-
queue_name,
|
|
3831
|
-
options->>'policy',
|
|
3832
|
-
COALESCE((options->>'retryLimit')::int, 2),
|
|
3833
|
-
COALESCE((options->>'retryDelay')::int, 0),
|
|
3834
|
-
COALESCE((options->>'retryBackoff')::bool, false),
|
|
3835
|
-
(options->>'retryDelayMax')::int,
|
|
3836
|
-
COALESCE((options->>'expireInSeconds')::int, 900),
|
|
3837
|
-
COALESCE((options->>'retentionSeconds')::int, 1209600),
|
|
3838
|
-
COALESCE((options->>'deleteAfterSeconds')::int, 604800),
|
|
3839
|
-
COALESCE((options->>'warningQueueSize')::int, 0),
|
|
3840
|
-
options->>'deadLetter',
|
|
3841
|
-
COALESCE((options->>'partition')::bool, false),
|
|
3842
|
-
tablename
|
|
3843
|
-
)
|
|
3844
|
-
ON CONFLICT DO NOTHING
|
|
3845
|
-
RETURNING created_on
|
|
3846
|
-
)
|
|
3847
|
-
SELECT created_on into queue_created_on from q;
|
|
3848
|
-
|
|
3849
|
-
IF queue_created_on IS NULL OR options->>'partition' IS DISTINCT FROM 'true' THEN
|
|
3850
|
-
RETURN;
|
|
3851
|
-
END IF;
|
|
3852
|
-
|
|
3853
|
-
EXECUTE format('CREATE TABLE ${schema}.%I (LIKE ${schema}.job INCLUDING DEFAULTS)', tablename);
|
|
3854
|
-
|
|
3855
|
-
EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD PRIMARY KEY (name, id)$cmd$, tablename);
|
|
3856
|
-
EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD CONSTRAINT q_fkey FOREIGN KEY (name) REFERENCES ${schema}.queue (name) ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED$cmd$, tablename);
|
|
3857
|
-
EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD CONSTRAINT dlq_fkey FOREIGN KEY (dead_letter) REFERENCES ${schema}.queue (name) ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED$cmd$, tablename);
|
|
3858
|
-
|
|
3859
|
-
EXECUTE ${schema}.job_table_format($cmd$CREATE INDEX job_i5 ON ${schema}.job (name, start_after) INCLUDE (priority, created_on, id) WHERE state < 'active'$cmd$, tablename);
|
|
3860
|
-
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i4 ON ${schema}.job (name, singleton_on, COALESCE(singleton_key, '')) WHERE state <> 'cancelled' AND singleton_on IS NOT NULL$cmd$, tablename);
|
|
3861
|
-
EXECUTE ${schema}.job_table_format($cmd$CREATE INDEX job_i7 ON ${schema}.job (name, group_id) WHERE state = 'active' AND group_id IS NOT NULL$cmd$, tablename);
|
|
3862
|
-
|
|
3863
|
-
IF options->>'policy' = 'short' THEN
|
|
3864
|
-
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i1 ON ${schema}.job (name, COALESCE(singleton_key, '')) WHERE state = 'created' AND policy = 'short'$cmd$, tablename);
|
|
3865
|
-
ELSIF options->>'policy' = 'singleton' THEN
|
|
3866
|
-
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i2 ON ${schema}.job (name, COALESCE(singleton_key, '')) WHERE state = 'active' AND policy = 'singleton'$cmd$, tablename);
|
|
3867
|
-
ELSIF options->>'policy' = 'stately' THEN
|
|
3868
|
-
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i3 ON ${schema}.job (name, state, COALESCE(singleton_key, '')) WHERE state <= 'active' AND policy = 'stately'$cmd$, tablename);
|
|
3869
|
-
ELSIF options->>'policy' = 'exclusive' THEN
|
|
3870
|
-
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i6 ON ${schema}.job (name, COALESCE(singleton_key, '')) WHERE state <= 'active' AND policy = 'exclusive'$cmd$, tablename);
|
|
3871
|
-
ELSIF options->>'policy' = 'key_strict_fifo' THEN
|
|
3872
|
-
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i8 ON ${schema}.job (name, singleton_key) WHERE state IN ('active', 'retry', 'failed') AND policy = 'key_strict_fifo'$cmd$, tablename);
|
|
3873
|
-
EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD CONSTRAINT job_key_strict_fifo_singleton_key_check CHECK (NOT (policy = 'key_strict_fifo' AND singleton_key IS NULL))$cmd$, tablename);
|
|
3874
|
-
END IF;
|
|
3875
|
-
|
|
3876
|
-
EXECUTE format('ALTER TABLE ${schema}.%I ADD CONSTRAINT cjc CHECK (name=%L)', tablename, queue_name);
|
|
3877
|
-
EXECUTE format('ALTER TABLE ${schema}.job ATTACH PARTITION ${schema}.%I FOR VALUES IN (%L)', tablename, queue_name);
|
|
3878
|
-
END;
|
|
3879
|
-
$$
|
|
3880
|
-
LANGUAGE plpgsql;
|
|
3881
|
-
`],
|
|
4409
|
+
install: [`SELECT ${schema}.job_table_run($cmd$ALTER TABLE ${schema}.job ADD CONSTRAINT job_key_strict_fifo_singleton_key_check CHECK (NOT (policy = 'key_strict_fifo' AND singleton_key IS NULL))$cmd$, 'job_common')`, createQueueFn[28](schema)],
|
|
3882
4410
|
async: [`SELECT ${schema}.job_table_run_async(
|
|
3883
4411
|
'key_strict_fifo_index',
|
|
3884
4412
|
$VERSION$,
|
|
@@ -3889,84 +4417,7 @@ function getAll(schema) {
|
|
|
3889
4417
|
uninstall: [
|
|
3890
4418
|
`SELECT ${schema}.job_table_run('DROP INDEX IF EXISTS ${schema}.job_i8')`,
|
|
3891
4419
|
`SELECT ${schema}.job_table_run('ALTER TABLE ${schema}.job DROP CONSTRAINT IF EXISTS job_key_strict_fifo_singleton_key_check')`,
|
|
3892
|
-
|
|
3893
|
-
CREATE OR REPLACE FUNCTION ${schema}.create_queue(queue_name text, options jsonb)
|
|
3894
|
-
RETURNS VOID AS
|
|
3895
|
-
$$
|
|
3896
|
-
DECLARE
|
|
3897
|
-
tablename varchar := CASE WHEN options->>'partition' = 'true'
|
|
3898
|
-
THEN 'j' || encode(sha224(queue_name::bytea), 'hex')
|
|
3899
|
-
ELSE 'job_common'
|
|
3900
|
-
END;
|
|
3901
|
-
queue_created_on timestamptz;
|
|
3902
|
-
BEGIN
|
|
3903
|
-
|
|
3904
|
-
WITH q as (
|
|
3905
|
-
INSERT INTO ${schema}.queue (
|
|
3906
|
-
name,
|
|
3907
|
-
policy,
|
|
3908
|
-
retry_limit,
|
|
3909
|
-
retry_delay,
|
|
3910
|
-
retry_backoff,
|
|
3911
|
-
retry_delay_max,
|
|
3912
|
-
expire_seconds,
|
|
3913
|
-
retention_seconds,
|
|
3914
|
-
deletion_seconds,
|
|
3915
|
-
warning_queued,
|
|
3916
|
-
dead_letter,
|
|
3917
|
-
partition,
|
|
3918
|
-
table_name
|
|
3919
|
-
)
|
|
3920
|
-
VALUES (
|
|
3921
|
-
queue_name,
|
|
3922
|
-
options->>'policy',
|
|
3923
|
-
COALESCE((options->>'retryLimit')::int, 2),
|
|
3924
|
-
COALESCE((options->>'retryDelay')::int, 0),
|
|
3925
|
-
COALESCE((options->>'retryBackoff')::bool, false),
|
|
3926
|
-
(options->>'retryDelayMax')::int,
|
|
3927
|
-
COALESCE((options->>'expireInSeconds')::int, 900),
|
|
3928
|
-
COALESCE((options->>'retentionSeconds')::int, 1209600),
|
|
3929
|
-
COALESCE((options->>'deleteAfterSeconds')::int, 604800),
|
|
3930
|
-
COALESCE((options->>'warningQueueSize')::int, 0),
|
|
3931
|
-
options->>'deadLetter',
|
|
3932
|
-
COALESCE((options->>'partition')::bool, false),
|
|
3933
|
-
tablename
|
|
3934
|
-
)
|
|
3935
|
-
ON CONFLICT DO NOTHING
|
|
3936
|
-
RETURNING created_on
|
|
3937
|
-
)
|
|
3938
|
-
SELECT created_on into queue_created_on from q;
|
|
3939
|
-
|
|
3940
|
-
IF queue_created_on IS NULL OR options->>'partition' IS DISTINCT FROM 'true' THEN
|
|
3941
|
-
RETURN;
|
|
3942
|
-
END IF;
|
|
3943
|
-
|
|
3944
|
-
EXECUTE format('CREATE TABLE ${schema}.%I (LIKE ${schema}.job INCLUDING DEFAULTS)', tablename);
|
|
3945
|
-
|
|
3946
|
-
EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD PRIMARY KEY (name, id)$cmd$, tablename);
|
|
3947
|
-
EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD CONSTRAINT q_fkey FOREIGN KEY (name) REFERENCES ${schema}.queue (name) ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED$cmd$, tablename);
|
|
3948
|
-
EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD CONSTRAINT dlq_fkey FOREIGN KEY (dead_letter) REFERENCES ${schema}.queue (name) ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED$cmd$, tablename);
|
|
3949
|
-
|
|
3950
|
-
EXECUTE ${schema}.job_table_format($cmd$CREATE INDEX job_i5 ON ${schema}.job (name, start_after) INCLUDE (priority, created_on, id) WHERE state < 'active'$cmd$, tablename);
|
|
3951
|
-
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i4 ON ${schema}.job (name, singleton_on, COALESCE(singleton_key, '')) WHERE state <> 'cancelled' AND singleton_on IS NOT NULL$cmd$, tablename);
|
|
3952
|
-
EXECUTE ${schema}.job_table_format($cmd$CREATE INDEX job_i7 ON ${schema}.job (name, group_id) WHERE state = 'active' AND group_id IS NOT NULL$cmd$, tablename);
|
|
3953
|
-
|
|
3954
|
-
IF options->>'policy' = 'short' THEN
|
|
3955
|
-
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i1 ON ${schema}.job (name, COALESCE(singleton_key, '')) WHERE state = 'created' AND policy = 'short'$cmd$, tablename);
|
|
3956
|
-
ELSIF options->>'policy' = 'singleton' THEN
|
|
3957
|
-
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i2 ON ${schema}.job (name, COALESCE(singleton_key, '')) WHERE state = 'active' AND policy = 'singleton'$cmd$, tablename);
|
|
3958
|
-
ELSIF options->>'policy' = 'stately' THEN
|
|
3959
|
-
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i3 ON ${schema}.job (name, state, COALESCE(singleton_key, '')) WHERE state <= 'active' AND policy = 'stately'$cmd$, tablename);
|
|
3960
|
-
ELSIF options->>'policy' = 'exclusive' THEN
|
|
3961
|
-
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i6 ON ${schema}.job (name, COALESCE(singleton_key, '')) WHERE state <= 'active' AND policy = 'exclusive'$cmd$, tablename);
|
|
3962
|
-
END IF;
|
|
3963
|
-
|
|
3964
|
-
EXECUTE format('ALTER TABLE ${schema}.%I ADD CONSTRAINT cjc CHECK (name=%L)', tablename, queue_name);
|
|
3965
|
-
EXECUTE format('ALTER TABLE ${schema}.job ATTACH PARTITION ${schema}.%I FOR VALUES IN (%L)', tablename, queue_name);
|
|
3966
|
-
END;
|
|
3967
|
-
$$
|
|
3968
|
-
LANGUAGE plpgsql;
|
|
3969
|
-
`
|
|
4420
|
+
createQueueFn[27](schema)
|
|
3970
4421
|
]
|
|
3971
4422
|
},
|
|
3972
4423
|
{
|
|
@@ -3986,176 +4437,14 @@ function getAll(schema) {
|
|
|
3986
4437
|
release: "12.12.0",
|
|
3987
4438
|
version: 30,
|
|
3988
4439
|
previous: 29,
|
|
3989
|
-
install: [
|
|
3990
|
-
`ALTER TABLE ${schema}.job ADD COLUMN heartbeat_on timestamp with time zone`,
|
|
3991
|
-
`ALTER TABLE ${schema}.job ADD COLUMN heartbeat_seconds int`,
|
|
3992
|
-
`ALTER TABLE ${schema}.queue ADD COLUMN heartbeat_seconds int`,
|
|
3993
|
-
|
|
3994
|
-
|
|
3995
|
-
|
|
3996
|
-
|
|
3997
|
-
DECLARE
|
|
3998
|
-
tablename varchar := CASE WHEN options->>'partition' = 'true'
|
|
3999
|
-
THEN 'j' || encode(sha224(queue_name::bytea), 'hex')
|
|
4000
|
-
ELSE 'job_common'
|
|
4001
|
-
END;
|
|
4002
|
-
queue_created_on timestamptz;
|
|
4003
|
-
BEGIN
|
|
4004
|
-
|
|
4005
|
-
WITH q as (
|
|
4006
|
-
INSERT INTO ${schema}.queue (
|
|
4007
|
-
name,
|
|
4008
|
-
policy,
|
|
4009
|
-
retry_limit,
|
|
4010
|
-
retry_delay,
|
|
4011
|
-
retry_backoff,
|
|
4012
|
-
retry_delay_max,
|
|
4013
|
-
expire_seconds,
|
|
4014
|
-
retention_seconds,
|
|
4015
|
-
deletion_seconds,
|
|
4016
|
-
warning_queued,
|
|
4017
|
-
dead_letter,
|
|
4018
|
-
partition,
|
|
4019
|
-
table_name,
|
|
4020
|
-
heartbeat_seconds
|
|
4021
|
-
)
|
|
4022
|
-
VALUES (
|
|
4023
|
-
queue_name,
|
|
4024
|
-
options->>'policy',
|
|
4025
|
-
COALESCE((options->>'retryLimit')::int, 2),
|
|
4026
|
-
COALESCE((options->>'retryDelay')::int, 0),
|
|
4027
|
-
COALESCE((options->>'retryBackoff')::bool, false),
|
|
4028
|
-
(options->>'retryDelayMax')::int,
|
|
4029
|
-
COALESCE((options->>'expireInSeconds')::int, 900),
|
|
4030
|
-
COALESCE((options->>'retentionSeconds')::int, 1209600),
|
|
4031
|
-
COALESCE((options->>'deleteAfterSeconds')::int, 604800),
|
|
4032
|
-
COALESCE((options->>'warningQueueSize')::int, 0),
|
|
4033
|
-
options->>'deadLetter',
|
|
4034
|
-
COALESCE((options->>'partition')::bool, false),
|
|
4035
|
-
tablename,
|
|
4036
|
-
(options->>'heartbeatSeconds')::int
|
|
4037
|
-
)
|
|
4038
|
-
ON CONFLICT DO NOTHING
|
|
4039
|
-
RETURNING created_on
|
|
4040
|
-
)
|
|
4041
|
-
SELECT created_on into queue_created_on from q;
|
|
4042
|
-
|
|
4043
|
-
IF queue_created_on IS NULL OR options->>'partition' IS DISTINCT FROM 'true' THEN
|
|
4044
|
-
RETURN;
|
|
4045
|
-
END IF;
|
|
4046
|
-
|
|
4047
|
-
EXECUTE format('CREATE TABLE ${schema}.%I (LIKE ${schema}.job INCLUDING DEFAULTS)', tablename);
|
|
4048
|
-
|
|
4049
|
-
EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD PRIMARY KEY (name, id)$cmd$, tablename);
|
|
4050
|
-
EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD CONSTRAINT q_fkey FOREIGN KEY (name) REFERENCES ${schema}.queue (name) ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED$cmd$, tablename);
|
|
4051
|
-
EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD CONSTRAINT dlq_fkey FOREIGN KEY (dead_letter) REFERENCES ${schema}.queue (name) ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED$cmd$, tablename);
|
|
4052
|
-
|
|
4053
|
-
EXECUTE ${schema}.job_table_format($cmd$CREATE INDEX job_i5 ON ${schema}.job (name, start_after) INCLUDE (priority, created_on, id) WHERE state < 'active'$cmd$, tablename);
|
|
4054
|
-
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i4 ON ${schema}.job (name, singleton_on, COALESCE(singleton_key, '')) WHERE state <> 'cancelled' AND singleton_on IS NOT NULL$cmd$, tablename);
|
|
4055
|
-
EXECUTE ${schema}.job_table_format($cmd$CREATE INDEX job_i7 ON ${schema}.job (name, group_id) WHERE state = 'active' AND group_id IS NOT NULL$cmd$, tablename);
|
|
4056
|
-
|
|
4057
|
-
IF options->>'policy' = 'short' THEN
|
|
4058
|
-
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i1 ON ${schema}.job (name, COALESCE(singleton_key, '')) WHERE state = 'created' AND policy = 'short'$cmd$, tablename);
|
|
4059
|
-
ELSIF options->>'policy' = 'singleton' THEN
|
|
4060
|
-
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i2 ON ${schema}.job (name, COALESCE(singleton_key, '')) WHERE state = 'active' AND policy = 'singleton'$cmd$, tablename);
|
|
4061
|
-
ELSIF options->>'policy' = 'stately' THEN
|
|
4062
|
-
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i3 ON ${schema}.job (name, state, COALESCE(singleton_key, '')) WHERE state <= 'active' AND policy = 'stately'$cmd$, tablename);
|
|
4063
|
-
ELSIF options->>'policy' = 'exclusive' THEN
|
|
4064
|
-
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i6 ON ${schema}.job (name, COALESCE(singleton_key, '')) WHERE state <= 'active' AND policy = 'exclusive'$cmd$, tablename);
|
|
4065
|
-
ELSIF options->>'policy' = 'key_strict_fifo' THEN
|
|
4066
|
-
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i8 ON ${schema}.job (name, singleton_key) WHERE state IN ('active', 'retry', 'failed') AND policy = 'key_strict_fifo'$cmd$, tablename);
|
|
4067
|
-
EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD CONSTRAINT job_key_strict_fifo_singleton_key_check CHECK (NOT (policy = 'key_strict_fifo' AND singleton_key IS NULL))$cmd$, tablename);
|
|
4068
|
-
END IF;
|
|
4069
|
-
|
|
4070
|
-
EXECUTE format('ALTER TABLE ${schema}.%I ADD CONSTRAINT cjc CHECK (name=%L)', tablename, queue_name);
|
|
4071
|
-
EXECUTE format('ALTER TABLE ${schema}.job ATTACH PARTITION ${schema}.%I FOR VALUES IN (%L)', tablename, queue_name);
|
|
4072
|
-
END;
|
|
4073
|
-
$$
|
|
4074
|
-
LANGUAGE plpgsql;
|
|
4075
|
-
`
|
|
4076
|
-
],
|
|
4077
|
-
uninstall: [
|
|
4078
|
-
`
|
|
4079
|
-
CREATE OR REPLACE FUNCTION ${schema}.create_queue(queue_name text, options jsonb)
|
|
4080
|
-
RETURNS VOID AS
|
|
4081
|
-
$$
|
|
4082
|
-
DECLARE
|
|
4083
|
-
tablename varchar := CASE WHEN options->>'partition' = 'true'
|
|
4084
|
-
THEN 'j' || encode(sha224(queue_name::bytea), 'hex')
|
|
4085
|
-
ELSE 'job_common'
|
|
4086
|
-
END;
|
|
4087
|
-
queue_created_on timestamptz;
|
|
4088
|
-
BEGIN
|
|
4089
|
-
|
|
4090
|
-
WITH q as (
|
|
4091
|
-
INSERT INTO ${schema}.queue (
|
|
4092
|
-
name,
|
|
4093
|
-
policy,
|
|
4094
|
-
retry_limit,
|
|
4095
|
-
retry_delay,
|
|
4096
|
-
retry_backoff,
|
|
4097
|
-
retry_delay_max,
|
|
4098
|
-
expire_seconds,
|
|
4099
|
-
retention_seconds,
|
|
4100
|
-
deletion_seconds,
|
|
4101
|
-
warning_queued,
|
|
4102
|
-
dead_letter,
|
|
4103
|
-
partition,
|
|
4104
|
-
table_name
|
|
4105
|
-
)
|
|
4106
|
-
VALUES (
|
|
4107
|
-
queue_name,
|
|
4108
|
-
options->>'policy',
|
|
4109
|
-
COALESCE((options->>'retryLimit')::int, 2),
|
|
4110
|
-
COALESCE((options->>'retryDelay')::int, 0),
|
|
4111
|
-
COALESCE((options->>'retryBackoff')::bool, false),
|
|
4112
|
-
(options->>'retryDelayMax')::int,
|
|
4113
|
-
COALESCE((options->>'expireInSeconds')::int, 900),
|
|
4114
|
-
COALESCE((options->>'retentionSeconds')::int, 1209600),
|
|
4115
|
-
COALESCE((options->>'deleteAfterSeconds')::int, 604800),
|
|
4116
|
-
COALESCE((options->>'warningQueueSize')::int, 0),
|
|
4117
|
-
options->>'deadLetter',
|
|
4118
|
-
COALESCE((options->>'partition')::bool, false),
|
|
4119
|
-
tablename
|
|
4120
|
-
)
|
|
4121
|
-
ON CONFLICT DO NOTHING
|
|
4122
|
-
RETURNING created_on
|
|
4123
|
-
)
|
|
4124
|
-
SELECT created_on into queue_created_on from q;
|
|
4125
|
-
|
|
4126
|
-
IF queue_created_on IS NULL OR options->>'partition' IS DISTINCT FROM 'true' THEN
|
|
4127
|
-
RETURN;
|
|
4128
|
-
END IF;
|
|
4129
|
-
|
|
4130
|
-
EXECUTE format('CREATE TABLE ${schema}.%I (LIKE ${schema}.job INCLUDING DEFAULTS)', tablename);
|
|
4131
|
-
|
|
4132
|
-
EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD PRIMARY KEY (name, id)$cmd$, tablename);
|
|
4133
|
-
EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD CONSTRAINT q_fkey FOREIGN KEY (name) REFERENCES ${schema}.queue (name) ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED$cmd$, tablename);
|
|
4134
|
-
EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD CONSTRAINT dlq_fkey FOREIGN KEY (dead_letter) REFERENCES ${schema}.queue (name) ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED$cmd$, tablename);
|
|
4135
|
-
|
|
4136
|
-
EXECUTE ${schema}.job_table_format($cmd$CREATE INDEX job_i5 ON ${schema}.job (name, start_after) INCLUDE (priority, created_on, id) WHERE state < 'active'$cmd$, tablename);
|
|
4137
|
-
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i4 ON ${schema}.job (name, singleton_on, COALESCE(singleton_key, '')) WHERE state <> 'cancelled' AND singleton_on IS NOT NULL$cmd$, tablename);
|
|
4138
|
-
EXECUTE ${schema}.job_table_format($cmd$CREATE INDEX job_i7 ON ${schema}.job (name, group_id) WHERE state = 'active' AND group_id IS NOT NULL$cmd$, tablename);
|
|
4139
|
-
|
|
4140
|
-
IF options->>'policy' = 'short' THEN
|
|
4141
|
-
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i1 ON ${schema}.job (name, COALESCE(singleton_key, '')) WHERE state = 'created' AND policy = 'short'$cmd$, tablename);
|
|
4142
|
-
ELSIF options->>'policy' = 'singleton' THEN
|
|
4143
|
-
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i2 ON ${schema}.job (name, COALESCE(singleton_key, '')) WHERE state = 'active' AND policy = 'singleton'$cmd$, tablename);
|
|
4144
|
-
ELSIF options->>'policy' = 'stately' THEN
|
|
4145
|
-
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i3 ON ${schema}.job (name, state, COALESCE(singleton_key, '')) WHERE state <= 'active' AND policy = 'stately'$cmd$, tablename);
|
|
4146
|
-
ELSIF options->>'policy' = 'exclusive' THEN
|
|
4147
|
-
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i6 ON ${schema}.job (name, COALESCE(singleton_key, '')) WHERE state <= 'active' AND policy = 'exclusive'$cmd$, tablename);
|
|
4148
|
-
ELSIF options->>'policy' = 'key_strict_fifo' THEN
|
|
4149
|
-
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i8 ON ${schema}.job (name, singleton_key) WHERE state IN ('active', 'retry', 'failed') AND policy = 'key_strict_fifo'$cmd$, tablename);
|
|
4150
|
-
EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD CONSTRAINT job_key_strict_fifo_singleton_key_check CHECK (NOT (policy = 'key_strict_fifo' AND singleton_key IS NULL))$cmd$, tablename);
|
|
4151
|
-
END IF;
|
|
4152
|
-
|
|
4153
|
-
EXECUTE format('ALTER TABLE ${schema}.%I ADD CONSTRAINT cjc CHECK (name=%L)', tablename, queue_name);
|
|
4154
|
-
EXECUTE format('ALTER TABLE ${schema}.job ATTACH PARTITION ${schema}.%I FOR VALUES IN (%L)', tablename, queue_name);
|
|
4155
|
-
END;
|
|
4156
|
-
$$
|
|
4157
|
-
LANGUAGE plpgsql;
|
|
4158
|
-
`,
|
|
4440
|
+
install: [
|
|
4441
|
+
`ALTER TABLE ${schema}.job ADD COLUMN heartbeat_on timestamp with time zone`,
|
|
4442
|
+
`ALTER TABLE ${schema}.job ADD COLUMN heartbeat_seconds int`,
|
|
4443
|
+
`ALTER TABLE ${schema}.queue ADD COLUMN heartbeat_seconds int`,
|
|
4444
|
+
createQueueFn[30](schema)
|
|
4445
|
+
],
|
|
4446
|
+
uninstall: [
|
|
4447
|
+
createQueueFn[28](schema),
|
|
4159
4448
|
`ALTER TABLE ${schema}.queue DROP COLUMN heartbeat_seconds`,
|
|
4160
4449
|
`ALTER TABLE ${schema}.job DROP COLUMN heartbeat_seconds`,
|
|
4161
4450
|
`ALTER TABLE ${schema}.job DROP COLUMN heartbeat_on`
|
|
@@ -4181,182 +4470,54 @@ function getAll(schema) {
|
|
|
4181
4470
|
`CREATE INDEX IF NOT EXISTS job_dep_parent_idx ON ${schema}.job_dependency (parent_name, parent_id)`,
|
|
4182
4471
|
`SELECT ${schema}.job_table_run($cmd$DROP INDEX IF EXISTS ${schema}.job_i5$cmd$)`,
|
|
4183
4472
|
`SELECT ${schema}.job_table_run($cmd$CREATE INDEX job_i5 ON ${schema}.job (name, start_after) INCLUDE (priority, created_on, id) WHERE state < 'active' AND NOT blocked$cmd$)`,
|
|
4184
|
-
|
|
4185
|
-
CREATE OR REPLACE FUNCTION ${schema}.create_queue(queue_name text, options jsonb)
|
|
4186
|
-
RETURNS VOID AS
|
|
4187
|
-
$$
|
|
4188
|
-
DECLARE
|
|
4189
|
-
tablename varchar := CASE WHEN options->>'partition' = 'true'
|
|
4190
|
-
THEN 'j' || encode(sha224(queue_name::bytea), 'hex')
|
|
4191
|
-
ELSE 'job_common'
|
|
4192
|
-
END;
|
|
4193
|
-
queue_created_on timestamptz;
|
|
4194
|
-
BEGIN
|
|
4195
|
-
|
|
4196
|
-
WITH q as (
|
|
4197
|
-
INSERT INTO ${schema}.queue (
|
|
4198
|
-
name,
|
|
4199
|
-
policy,
|
|
4200
|
-
retry_limit,
|
|
4201
|
-
retry_delay,
|
|
4202
|
-
retry_backoff,
|
|
4203
|
-
retry_delay_max,
|
|
4204
|
-
expire_seconds,
|
|
4205
|
-
retention_seconds,
|
|
4206
|
-
deletion_seconds,
|
|
4207
|
-
warning_queued,
|
|
4208
|
-
dead_letter,
|
|
4209
|
-
partition,
|
|
4210
|
-
table_name,
|
|
4211
|
-
heartbeat_seconds
|
|
4212
|
-
)
|
|
4213
|
-
VALUES (
|
|
4214
|
-
queue_name,
|
|
4215
|
-
options->>'policy',
|
|
4216
|
-
COALESCE((options->>'retryLimit')::int, 2),
|
|
4217
|
-
COALESCE((options->>'retryDelay')::int, 0),
|
|
4218
|
-
COALESCE((options->>'retryBackoff')::bool, false),
|
|
4219
|
-
(options->>'retryDelayMax')::int,
|
|
4220
|
-
COALESCE((options->>'expireInSeconds')::int, 900),
|
|
4221
|
-
COALESCE((options->>'retentionSeconds')::int, 1209600),
|
|
4222
|
-
COALESCE((options->>'deleteAfterSeconds')::int, 604800),
|
|
4223
|
-
COALESCE((options->>'warningQueueSize')::int, 0),
|
|
4224
|
-
options->>'deadLetter',
|
|
4225
|
-
COALESCE((options->>'partition')::bool, false),
|
|
4226
|
-
tablename,
|
|
4227
|
-
(options->>'heartbeatSeconds')::int
|
|
4228
|
-
)
|
|
4229
|
-
ON CONFLICT DO NOTHING
|
|
4230
|
-
RETURNING created_on
|
|
4231
|
-
)
|
|
4232
|
-
SELECT created_on into queue_created_on from q;
|
|
4233
|
-
|
|
4234
|
-
IF queue_created_on IS NULL OR options->>'partition' IS DISTINCT FROM 'true' THEN
|
|
4235
|
-
RETURN;
|
|
4236
|
-
END IF;
|
|
4237
|
-
|
|
4238
|
-
EXECUTE format('CREATE TABLE ${schema}.%I (LIKE ${schema}.job INCLUDING DEFAULTS)', tablename);
|
|
4239
|
-
|
|
4240
|
-
EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD PRIMARY KEY (name, id)$cmd$, tablename);
|
|
4241
|
-
EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD CONSTRAINT q_fkey FOREIGN KEY (name) REFERENCES ${schema}.queue (name) ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED$cmd$, tablename);
|
|
4242
|
-
EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD CONSTRAINT dlq_fkey FOREIGN KEY (dead_letter) REFERENCES ${schema}.queue (name) ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED$cmd$, tablename);
|
|
4243
|
-
|
|
4244
|
-
EXECUTE ${schema}.job_table_format($cmd$CREATE INDEX job_i5 ON ${schema}.job (name, start_after) INCLUDE (priority, created_on, id) WHERE state < 'active' AND NOT blocked$cmd$, tablename);
|
|
4245
|
-
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i4 ON ${schema}.job (name, singleton_on, COALESCE(singleton_key, '')) WHERE state <> 'cancelled' AND singleton_on IS NOT NULL$cmd$, tablename);
|
|
4246
|
-
EXECUTE ${schema}.job_table_format($cmd$CREATE INDEX job_i7 ON ${schema}.job (name, group_id) WHERE state = 'active' AND group_id IS NOT NULL$cmd$, tablename);
|
|
4247
|
-
|
|
4248
|
-
IF options->>'policy' = 'short' THEN
|
|
4249
|
-
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i1 ON ${schema}.job (name, COALESCE(singleton_key, '')) WHERE state = 'created' AND policy = 'short'$cmd$, tablename);
|
|
4250
|
-
ELSIF options->>'policy' = 'singleton' THEN
|
|
4251
|
-
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i2 ON ${schema}.job (name, COALESCE(singleton_key, '')) WHERE state = 'active' AND policy = 'singleton'$cmd$, tablename);
|
|
4252
|
-
ELSIF options->>'policy' = 'stately' THEN
|
|
4253
|
-
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i3 ON ${schema}.job (name, state, COALESCE(singleton_key, '')) WHERE state <= 'active' AND policy = 'stately'$cmd$, tablename);
|
|
4254
|
-
ELSIF options->>'policy' = 'exclusive' THEN
|
|
4255
|
-
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i6 ON ${schema}.job (name, COALESCE(singleton_key, '')) WHERE state <= 'active' AND policy = 'exclusive'$cmd$, tablename);
|
|
4256
|
-
ELSIF options->>'policy' = 'key_strict_fifo' THEN
|
|
4257
|
-
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i8 ON ${schema}.job (name, singleton_key) WHERE state IN ('active', 'retry', 'failed') AND policy = 'key_strict_fifo'$cmd$, tablename);
|
|
4258
|
-
EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD CONSTRAINT job_key_strict_fifo_singleton_key_check CHECK (NOT (policy = 'key_strict_fifo' AND singleton_key IS NULL))$cmd$, tablename);
|
|
4259
|
-
END IF;
|
|
4260
|
-
|
|
4261
|
-
EXECUTE format('ALTER TABLE ${schema}.%I ADD CONSTRAINT cjc CHECK (name=%L)', tablename, queue_name);
|
|
4262
|
-
EXECUTE format('ALTER TABLE ${schema}.job ATTACH PARTITION ${schema}.%I FOR VALUES IN (%L)', tablename, queue_name);
|
|
4263
|
-
END;
|
|
4264
|
-
$$
|
|
4265
|
-
LANGUAGE plpgsql;
|
|
4266
|
-
`
|
|
4473
|
+
createQueueFn[31](schema)
|
|
4267
4474
|
],
|
|
4268
4475
|
uninstall: [
|
|
4269
4476
|
`DROP INDEX IF EXISTS ${schema}.job_dep_parent_idx`,
|
|
4270
4477
|
`DROP TABLE IF EXISTS ${schema}.job_dependency`,
|
|
4271
|
-
|
|
4272
|
-
CREATE OR REPLACE FUNCTION ${schema}.create_queue(queue_name text, options jsonb)
|
|
4273
|
-
RETURNS VOID AS
|
|
4274
|
-
$$
|
|
4275
|
-
DECLARE
|
|
4276
|
-
tablename varchar := CASE WHEN options->>'partition' = 'true'
|
|
4277
|
-
THEN 'j' || encode(sha224(queue_name::bytea), 'hex')
|
|
4278
|
-
ELSE 'job_common'
|
|
4279
|
-
END;
|
|
4280
|
-
queue_created_on timestamptz;
|
|
4281
|
-
BEGIN
|
|
4282
|
-
|
|
4283
|
-
WITH q as (
|
|
4284
|
-
INSERT INTO ${schema}.queue (
|
|
4285
|
-
name,
|
|
4286
|
-
policy,
|
|
4287
|
-
retry_limit,
|
|
4288
|
-
retry_delay,
|
|
4289
|
-
retry_backoff,
|
|
4290
|
-
retry_delay_max,
|
|
4291
|
-
expire_seconds,
|
|
4292
|
-
retention_seconds,
|
|
4293
|
-
deletion_seconds,
|
|
4294
|
-
warning_queued,
|
|
4295
|
-
dead_letter,
|
|
4296
|
-
partition,
|
|
4297
|
-
table_name,
|
|
4298
|
-
heartbeat_seconds
|
|
4299
|
-
)
|
|
4300
|
-
VALUES (
|
|
4301
|
-
queue_name,
|
|
4302
|
-
options->>'policy',
|
|
4303
|
-
COALESCE((options->>'retryLimit')::int, 2),
|
|
4304
|
-
COALESCE((options->>'retryDelay')::int, 0),
|
|
4305
|
-
COALESCE((options->>'retryBackoff')::bool, false),
|
|
4306
|
-
(options->>'retryDelayMax')::int,
|
|
4307
|
-
COALESCE((options->>'expireInSeconds')::int, 900),
|
|
4308
|
-
COALESCE((options->>'retentionSeconds')::int, 1209600),
|
|
4309
|
-
COALESCE((options->>'deleteAfterSeconds')::int, 604800),
|
|
4310
|
-
COALESCE((options->>'warningQueueSize')::int, 0),
|
|
4311
|
-
options->>'deadLetter',
|
|
4312
|
-
COALESCE((options->>'partition')::bool, false),
|
|
4313
|
-
tablename,
|
|
4314
|
-
(options->>'heartbeatSeconds')::int
|
|
4315
|
-
)
|
|
4316
|
-
ON CONFLICT DO NOTHING
|
|
4317
|
-
RETURNING created_on
|
|
4318
|
-
)
|
|
4319
|
-
SELECT created_on into queue_created_on from q;
|
|
4320
|
-
|
|
4321
|
-
IF queue_created_on IS NULL OR options->>'partition' IS DISTINCT FROM 'true' THEN
|
|
4322
|
-
RETURN;
|
|
4323
|
-
END IF;
|
|
4324
|
-
|
|
4325
|
-
EXECUTE format('CREATE TABLE ${schema}.%I (LIKE ${schema}.job INCLUDING DEFAULTS)', tablename);
|
|
4326
|
-
|
|
4327
|
-
EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD PRIMARY KEY (name, id)$cmd$, tablename);
|
|
4328
|
-
EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD CONSTRAINT q_fkey FOREIGN KEY (name) REFERENCES ${schema}.queue (name) ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED$cmd$, tablename);
|
|
4329
|
-
EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD CONSTRAINT dlq_fkey FOREIGN KEY (dead_letter) REFERENCES ${schema}.queue (name) ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED$cmd$, tablename);
|
|
4330
|
-
|
|
4331
|
-
EXECUTE ${schema}.job_table_format($cmd$CREATE INDEX job_i5 ON ${schema}.job (name, start_after) INCLUDE (priority, created_on, id) WHERE state < 'active'$cmd$, tablename);
|
|
4332
|
-
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i4 ON ${schema}.job (name, singleton_on, COALESCE(singleton_key, '')) WHERE state <> 'cancelled' AND singleton_on IS NOT NULL$cmd$, tablename);
|
|
4333
|
-
EXECUTE ${schema}.job_table_format($cmd$CREATE INDEX job_i7 ON ${schema}.job (name, group_id) WHERE state = 'active' AND group_id IS NOT NULL$cmd$, tablename);
|
|
4334
|
-
|
|
4335
|
-
IF options->>'policy' = 'short' THEN
|
|
4336
|
-
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i1 ON ${schema}.job (name, COALESCE(singleton_key, '')) WHERE state = 'created' AND policy = 'short'$cmd$, tablename);
|
|
4337
|
-
ELSIF options->>'policy' = 'singleton' THEN
|
|
4338
|
-
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i2 ON ${schema}.job (name, COALESCE(singleton_key, '')) WHERE state = 'active' AND policy = 'singleton'$cmd$, tablename);
|
|
4339
|
-
ELSIF options->>'policy' = 'stately' THEN
|
|
4340
|
-
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i3 ON ${schema}.job (name, state, COALESCE(singleton_key, '')) WHERE state <= 'active' AND policy = 'stately'$cmd$, tablename);
|
|
4341
|
-
ELSIF options->>'policy' = 'exclusive' THEN
|
|
4342
|
-
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i6 ON ${schema}.job (name, COALESCE(singleton_key, '')) WHERE state <= 'active' AND policy = 'exclusive'$cmd$, tablename);
|
|
4343
|
-
ELSIF options->>'policy' = 'key_strict_fifo' THEN
|
|
4344
|
-
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i8 ON ${schema}.job (name, singleton_key) WHERE state IN ('active', 'retry', 'failed') AND policy = 'key_strict_fifo'$cmd$, tablename);
|
|
4345
|
-
EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD CONSTRAINT job_key_strict_fifo_singleton_key_check CHECK (NOT (policy = 'key_strict_fifo' AND singleton_key IS NULL))$cmd$, tablename);
|
|
4346
|
-
END IF;
|
|
4347
|
-
|
|
4348
|
-
EXECUTE format('ALTER TABLE ${schema}.%I ADD CONSTRAINT cjc CHECK (name=%L)', tablename, queue_name);
|
|
4349
|
-
EXECUTE format('ALTER TABLE ${schema}.job ATTACH PARTITION ${schema}.%I FOR VALUES IN (%L)', tablename, queue_name);
|
|
4350
|
-
END;
|
|
4351
|
-
$$
|
|
4352
|
-
LANGUAGE plpgsql;
|
|
4353
|
-
`,
|
|
4478
|
+
createQueueFn[30](schema),
|
|
4354
4479
|
`SELECT ${schema}.job_table_run($cmd$DROP INDEX IF EXISTS ${schema}.job_i5$cmd$)`,
|
|
4355
4480
|
`SELECT ${schema}.job_table_run($cmd$CREATE INDEX job_i5 ON ${schema}.job (name, start_after) INCLUDE (priority, created_on, id) WHERE state < 'active'$cmd$)`,
|
|
4356
4481
|
`ALTER TABLE ${schema}.job DROP COLUMN pending_dependencies`,
|
|
4357
4482
|
`ALTER TABLE ${schema}.job DROP COLUMN blocking`,
|
|
4358
4483
|
`ALTER TABLE ${schema}.job DROP COLUMN blocked`
|
|
4359
4484
|
]
|
|
4485
|
+
},
|
|
4486
|
+
{
|
|
4487
|
+
release: "12.21.0",
|
|
4488
|
+
version: 32,
|
|
4489
|
+
previous: 31,
|
|
4490
|
+
install: [
|
|
4491
|
+
`ALTER TABLE ${schema}.queue ADD COLUMN notify boolean NOT NULL DEFAULT false`,
|
|
4492
|
+
createQueueFn[32](schema),
|
|
4493
|
+
`ALTER TABLE ${schema}.queue ADD COLUMN failed_count int NOT NULL DEFAULT 0`,
|
|
4494
|
+
`ALTER TABLE ${schema}.queue ADD COLUMN ready_count int NOT NULL DEFAULT 0`
|
|
4495
|
+
],
|
|
4496
|
+
uninstall: [
|
|
4497
|
+
`ALTER TABLE ${schema}.queue DROP COLUMN ready_count`,
|
|
4498
|
+
`ALTER TABLE ${schema}.queue DROP COLUMN failed_count`,
|
|
4499
|
+
createQueueFn[31](schema),
|
|
4500
|
+
`ALTER TABLE ${schema}.queue DROP COLUMN notify`
|
|
4501
|
+
]
|
|
4502
|
+
},
|
|
4503
|
+
{
|
|
4504
|
+
release: "12.22.0",
|
|
4505
|
+
version: 33,
|
|
4506
|
+
previous: 32,
|
|
4507
|
+
install: [
|
|
4508
|
+
`ALTER TABLE ${schema}.version ADD COLUMN IF NOT EXISTS flow_on timestamp with time zone`,
|
|
4509
|
+
`SELECT ${schema}.job_table_run($cmd$CREATE INDEX job_i9 ON ${schema}.job (name, id) WHERE blocking AND state = 'completed'$cmd$)`,
|
|
4510
|
+
`SELECT ${schema}.job_table_run($cmd$DROP INDEX IF EXISTS ${schema}.job_i5$cmd$)`,
|
|
4511
|
+
`SELECT ${schema}.job_table_run($cmd$CREATE INDEX job_i5 ON ${schema}.job (name, start_after) WHERE state < 'active' AND NOT blocked$cmd$)`,
|
|
4512
|
+
createQueueFn[33](schema)
|
|
4513
|
+
],
|
|
4514
|
+
uninstall: [
|
|
4515
|
+
createQueueFn[32](schema),
|
|
4516
|
+
`SELECT ${schema}.job_table_run($cmd$DROP INDEX IF EXISTS ${schema}.job_i5$cmd$)`,
|
|
4517
|
+
`SELECT ${schema}.job_table_run($cmd$CREATE INDEX job_i5 ON ${schema}.job (name, start_after) INCLUDE (priority, created_on, id) WHERE state < 'active' AND NOT blocked$cmd$)`,
|
|
4518
|
+
`SELECT ${schema}.job_table_run($cmd$DROP INDEX IF EXISTS ${schema}.job_i9$cmd$)`,
|
|
4519
|
+
`ALTER TABLE ${schema}.version DROP COLUMN flow_on`
|
|
4520
|
+
]
|
|
4360
4521
|
}
|
|
4361
4522
|
];
|
|
4362
4523
|
}
|
|
@@ -4364,7 +4525,7 @@ function getAll(schema) {
|
|
|
4364
4525
|
//#region ../../src/contractor.ts
|
|
4365
4526
|
var schemaVersion = {
|
|
4366
4527
|
name: "pg-boss",
|
|
4367
|
-
version: "12.
|
|
4528
|
+
version: "12.22.0",
|
|
4368
4529
|
description: "Queueing jobs in Postgres from Node.js like a boss",
|
|
4369
4530
|
type: "module",
|
|
4370
4531
|
main: "./dist/index.js",
|
|
@@ -4372,18 +4533,18 @@ var schemaVersion = {
|
|
|
4372
4533
|
bin: { "pg-boss": "./dist/cli.js" },
|
|
4373
4534
|
engines: { "node": ">=22.12.0" },
|
|
4374
4535
|
dependencies: {
|
|
4375
|
-
"cron-parser": "^5.
|
|
4376
|
-
"pg": "^8.
|
|
4536
|
+
"cron-parser": "^5.6.1",
|
|
4537
|
+
"pg": "^8.22.0",
|
|
4377
4538
|
"serialize-error": "^13.0.1"
|
|
4378
4539
|
},
|
|
4379
4540
|
devDependencies: {
|
|
4380
|
-
"@electric-sql/pglite": "^0.
|
|
4541
|
+
"@electric-sql/pglite": "^0.5.3",
|
|
4381
4542
|
"@prisma/adapter-pg": "^7.8.0",
|
|
4382
4543
|
"@prisma/client": "^7.8.0",
|
|
4383
4544
|
"@tsconfig/node-ts": "^23.6.4",
|
|
4384
4545
|
"@tsconfig/node22": "^22.0.5",
|
|
4385
|
-
"@types/luxon": "^3.7.
|
|
4386
|
-
"@types/node": "^22.
|
|
4546
|
+
"@types/luxon": "^3.7.2",
|
|
4547
|
+
"@types/node": "^22.20.0",
|
|
4387
4548
|
"@types/pg": "^8.20.0",
|
|
4388
4549
|
"@vitest/coverage-v8": "^4.1.2",
|
|
4389
4550
|
"cli-testlab": "^6.0.1",
|
|
@@ -4403,23 +4564,24 @@ var schemaVersion = {
|
|
|
4403
4564
|
"build": "npm run clean && tsc --project tsconfig.build.json",
|
|
4404
4565
|
"clean": "node -e \"fs.rmSync('dist',{recursive:true,force:true})\"",
|
|
4405
4566
|
"prepublishOnly": "npm install && npm test && npm run build",
|
|
4406
|
-
"pretest": "prisma generate --schema=test/prisma/schema.prisma",
|
|
4567
|
+
"pretest": "prisma generate --schema=test/prisma/schema.prisma && npm run tsc",
|
|
4407
4568
|
"test": "eslint . && vitest run",
|
|
4408
4569
|
"test:distributed": "cross-env DISTRIBUTED=true npm test",
|
|
4570
|
+
"test:ci": "npm run cover && cross-env DISTRIBUTED=true npm run cover && npm run test:pglite",
|
|
4409
4571
|
"test:cockroachdb": "cross-env DB_TYPE=cockroachdb COCKROACH_HOST=localhost npm test -- test/distributedDatabaseTest.ts",
|
|
4410
4572
|
"test:cockroachdb:full": "cross-env DB_TYPE=cockroachdb COCKROACH_HOST=localhost npm test -- --no-file-parallelism",
|
|
4411
4573
|
"test:yugabytedb:full": "cross-env DB_TYPE=yugabytedb YUGABYTE_HOST=localhost npm test -- --no-file-parallelism",
|
|
4412
4574
|
"test:citus:full": "cross-env DB_TYPE=citus CITUS_HOST=localhost npm test",
|
|
4413
4575
|
"test:pglite": "cross-env DB_TYPE=pglite npm test -- --no-file-parallelism",
|
|
4414
4576
|
"lint:fix": "eslint . --fix",
|
|
4415
|
-
"
|
|
4416
|
-
"cover": "vitest run --coverage",
|
|
4577
|
+
"cover": "npm test -- --coverage",
|
|
4417
4578
|
"tsc": "tsc --noEmit",
|
|
4579
|
+
"cli": "node ./dist/cli.js",
|
|
4418
4580
|
"readme": "node ./examples/readme.js",
|
|
4419
|
-
"
|
|
4420
|
-
"
|
|
4581
|
+
"docs": "npm run docs:dev --prefix docs",
|
|
4582
|
+
"docs:readme": "node ./scripts/sync-readme.js"
|
|
4421
4583
|
},
|
|
4422
|
-
pgboss: { "schema":
|
|
4584
|
+
pgboss: { "schema": 33 },
|
|
4423
4585
|
repository: {
|
|
4424
4586
|
"type": "git",
|
|
4425
4587
|
"url": "git+https://github.com/timgit/pg-boss.git"
|
|
@@ -4445,8 +4607,11 @@ var Contractor = class {
|
|
|
4445
4607
|
static constructionPlans(schema = DEFAULT_SCHEMA, options = { createSchema: true }) {
|
|
4446
4608
|
return create(schema, schemaVersion, options);
|
|
4447
4609
|
}
|
|
4448
|
-
static migrationPlans(schema = DEFAULT_SCHEMA, version = schemaVersion - 1) {
|
|
4449
|
-
return migrate(schema, version
|
|
4610
|
+
static migrationPlans(schema = DEFAULT_SCHEMA, version = schemaVersion - 1, options = {}) {
|
|
4611
|
+
return migrate(schema, version, void 0, void 0, {
|
|
4612
|
+
inlineAsync: true,
|
|
4613
|
+
partitionTables: options.partitionTables
|
|
4614
|
+
});
|
|
4450
4615
|
}
|
|
4451
4616
|
static rollbackPlans(schema = DEFAULT_SCHEMA, version = schemaVersion) {
|
|
4452
4617
|
return rollback(schema, version);
|
|
@@ -4741,7 +4906,7 @@ var Worker = class {
|
|
|
4741
4906
|
fetch;
|
|
4742
4907
|
onFetch;
|
|
4743
4908
|
onError;
|
|
4744
|
-
|
|
4909
|
+
resolveInterval;
|
|
4745
4910
|
jobs = [];
|
|
4746
4911
|
createdOn = Date.now();
|
|
4747
4912
|
state = WORKER_STATES.created;
|
|
@@ -4757,7 +4922,7 @@ var Worker = class {
|
|
|
4757
4922
|
loopDelayPromise = null;
|
|
4758
4923
|
beenNotified = false;
|
|
4759
4924
|
runPromise = null;
|
|
4760
|
-
constructor({ id, workId, name, options,
|
|
4925
|
+
constructor({ id, workId, name, options, resolveInterval, fetch, onFetch, onError }) {
|
|
4761
4926
|
this.id = id;
|
|
4762
4927
|
this.workId = workId;
|
|
4763
4928
|
this.name = name;
|
|
@@ -4765,7 +4930,7 @@ var Worker = class {
|
|
|
4765
4930
|
this.fetch = fetch;
|
|
4766
4931
|
this.onFetch = onFetch;
|
|
4767
4932
|
this.onError = onError;
|
|
4768
|
-
this.
|
|
4933
|
+
this.resolveInterval = resolveInterval;
|
|
4769
4934
|
}
|
|
4770
4935
|
start() {
|
|
4771
4936
|
this.runPromise = this.run();
|
|
@@ -4774,11 +4939,13 @@ var Worker = class {
|
|
|
4774
4939
|
this.state = WORKER_STATES.active;
|
|
4775
4940
|
while (!this.stopping) {
|
|
4776
4941
|
const started = Date.now();
|
|
4942
|
+
let fetchedCount = 0;
|
|
4777
4943
|
try {
|
|
4778
4944
|
this.beenNotified = false;
|
|
4779
4945
|
const jobs = await this.fetch();
|
|
4780
4946
|
this.lastFetchedOn = Date.now();
|
|
4781
4947
|
if (jobs) {
|
|
4948
|
+
fetchedCount = jobs.length;
|
|
4782
4949
|
this.jobs = jobs;
|
|
4783
4950
|
this.lastJobStartedOn = this.lastFetchedOn;
|
|
4784
4951
|
await this.onFetch(jobs);
|
|
@@ -4793,8 +4960,9 @@ var Worker = class {
|
|
|
4793
4960
|
}
|
|
4794
4961
|
const duration = Date.now() - started;
|
|
4795
4962
|
this.lastJobDuration = duration;
|
|
4796
|
-
|
|
4797
|
-
|
|
4963
|
+
const interval = this.resolveInterval(fetchedCount);
|
|
4964
|
+
if (!this.stopping && !this.beenNotified && interval - duration > 100) {
|
|
4965
|
+
this.loopDelayPromise = delay(interval - duration);
|
|
4798
4966
|
await this.loopDelayPromise;
|
|
4799
4967
|
this.loopDelayPromise = null;
|
|
4800
4968
|
}
|
|
@@ -4927,7 +5095,7 @@ var NUMERIC_QUEUE_FIELDS = [
|
|
|
4927
5095
|
"activeCount",
|
|
4928
5096
|
"totalCount"
|
|
4929
5097
|
];
|
|
4930
|
-
var events$
|
|
5098
|
+
var events$5 = {
|
|
4931
5099
|
error: "error",
|
|
4932
5100
|
wip: "wip"
|
|
4933
5101
|
};
|
|
@@ -4936,7 +5104,7 @@ function rethrowWriteError(err) {
|
|
|
4936
5104
|
throw err;
|
|
4937
5105
|
}
|
|
4938
5106
|
var Manager = class extends EventEmitter {
|
|
4939
|
-
events = events$
|
|
5107
|
+
events = events$5;
|
|
4940
5108
|
db;
|
|
4941
5109
|
config;
|
|
4942
5110
|
wipTs;
|
|
@@ -4945,6 +5113,7 @@ var Manager = class extends EventEmitter {
|
|
|
4945
5113
|
queueCacheInterval;
|
|
4946
5114
|
wipInterval;
|
|
4947
5115
|
timekeeper;
|
|
5116
|
+
notifier;
|
|
4948
5117
|
queues;
|
|
4949
5118
|
pendingOffWorkCleanups;
|
|
4950
5119
|
#spies;
|
|
@@ -5013,19 +5182,134 @@ var Manager = class extends EventEmitter {
|
|
|
5013
5182
|
const spy = this.config.__test__enableSpies ? this.#spies.get(name) : void 0;
|
|
5014
5183
|
if (spy) for (const job of jobs) spy.addJob(job.id, name, job.data, "active");
|
|
5015
5184
|
}
|
|
5016
|
-
#trackJobsCompleted(name, jobs, result) {
|
|
5185
|
+
async #trackJobsCompleted(name, jobs, result, affected) {
|
|
5017
5186
|
const spy = this.config.__test__enableSpies ? this.#spies.get(name) : void 0;
|
|
5018
|
-
if (spy)
|
|
5187
|
+
if (!spy) return;
|
|
5188
|
+
if (affected === jobs.length) {
|
|
5019
5189
|
const output = jobs.length === 1 ? result : void 0;
|
|
5020
5190
|
for (const job of jobs) spy.addJob(job.id, name, job.data, "completed", output);
|
|
5191
|
+
return;
|
|
5192
|
+
}
|
|
5193
|
+
for (const job of jobs) {
|
|
5194
|
+
const persisted = await this.getJobById(name, job.id);
|
|
5195
|
+
const state = persisted?.state;
|
|
5196
|
+
if (state === "completed" || state === "failed" || state === "active" || state === "created") spy.addJob(job.id, name, job.data, state, persisted?.output);
|
|
5197
|
+
else if (!persisted) spy.addJob(job.id, name, job.data, "completed", void 0);
|
|
5021
5198
|
}
|
|
5022
5199
|
}
|
|
5023
|
-
#trackJobsFailed(name, jobs, err) {
|
|
5200
|
+
async #trackJobsFailed(name, jobs, err) {
|
|
5024
5201
|
const spy = this.config.__test__enableSpies ? this.#spies.get(name) : void 0;
|
|
5025
|
-
if (spy)
|
|
5026
|
-
|
|
5027
|
-
|
|
5028
|
-
|
|
5202
|
+
if (!spy) return;
|
|
5203
|
+
for (const job of jobs) {
|
|
5204
|
+
const persisted = await this.getJobById(name, job.id);
|
|
5205
|
+
if (persisted?.state === "failed") spy.addJob(job.id, name, job.data, "failed", persisted.output ?? {
|
|
5206
|
+
message: err?.message,
|
|
5207
|
+
stack: err?.stack
|
|
5208
|
+
});
|
|
5209
|
+
}
|
|
5210
|
+
}
|
|
5211
|
+
#trackJobsSettled(name, completed, failed) {
|
|
5212
|
+
const spy = this.config.__test__enableSpies ? this.#spies.get(name) : void 0;
|
|
5213
|
+
if (!spy) return;
|
|
5214
|
+
for (const { job, output } of completed) spy.addJob(job.id, name, job.data, "completed", output);
|
|
5215
|
+
for (const { job, output } of failed) spy.addJob(job.id, name, job.data, "failed", serializeError(output));
|
|
5216
|
+
}
|
|
5217
|
+
async #settlePerJob(name, jobs, result) {
|
|
5218
|
+
if (!Array.isArray(result)) {
|
|
5219
|
+
const err = /* @__PURE__ */ new Error("perJobResults handler must resolve with an array of job results");
|
|
5220
|
+
await this.fail(name, jobs.map((job) => job.id), err);
|
|
5221
|
+
this.#trackJobsFailed(name, jobs, err);
|
|
5222
|
+
return;
|
|
5223
|
+
}
|
|
5224
|
+
const batch = new Map(jobs.map((job) => [job.id, job]));
|
|
5225
|
+
const disposition = /* @__PURE__ */ new Map();
|
|
5226
|
+
for (const item of result) if (item && batch.has(item.id) && (item.status === "completed" || item.status === "failed" || item.status === "deadletter")) disposition.set(item.id, item);
|
|
5227
|
+
const completed = [];
|
|
5228
|
+
const failed = [];
|
|
5229
|
+
const deadLettered = [];
|
|
5230
|
+
for (const job of jobs) {
|
|
5231
|
+
const item = disposition.get(job.id);
|
|
5232
|
+
if (item?.status === "completed") completed.push({
|
|
5233
|
+
job,
|
|
5234
|
+
output: item.output
|
|
5235
|
+
});
|
|
5236
|
+
else if (item?.status === "failed") failed.push({
|
|
5237
|
+
job,
|
|
5238
|
+
output: item.output
|
|
5239
|
+
});
|
|
5240
|
+
else if (item?.status === "deadletter") deadLettered.push({
|
|
5241
|
+
job,
|
|
5242
|
+
output: item.output
|
|
5243
|
+
});
|
|
5244
|
+
else failed.push({
|
|
5245
|
+
job,
|
|
5246
|
+
output: /* @__PURE__ */ new Error("no disposition returned by handler")
|
|
5247
|
+
});
|
|
5248
|
+
}
|
|
5249
|
+
if (completed.length > 0) await this.#completeWithOutputs(name, completed.map((c) => ({
|
|
5250
|
+
id: c.job.id,
|
|
5251
|
+
output: c.output
|
|
5252
|
+
})));
|
|
5253
|
+
if (failed.length > 0) await this.#failWithOutputs(name, failed.map((f) => ({
|
|
5254
|
+
id: f.job.id,
|
|
5255
|
+
output: f.output
|
|
5256
|
+
})));
|
|
5257
|
+
if (deadLettered.length > 0) await this.#failWithOutputs(name, deadLettered.map((d) => ({
|
|
5258
|
+
id: d.job.id,
|
|
5259
|
+
output: d.output
|
|
5260
|
+
})), true);
|
|
5261
|
+
this.#trackJobsSettled(name, completed, [...failed, ...deadLettered]);
|
|
5262
|
+
}
|
|
5263
|
+
async #completeWithOutputs(name, items) {
|
|
5264
|
+
const { table } = await this.getQueueCache(name);
|
|
5265
|
+
const payload = items.map((item) => ({
|
|
5266
|
+
id: item.id,
|
|
5267
|
+
output: this.mapCompletionDataArg(item.output)
|
|
5268
|
+
}));
|
|
5269
|
+
const ids = items.map((item) => item.id);
|
|
5270
|
+
if (this.config.noMultiMutationCte) {
|
|
5271
|
+
const sql = completeJobsWithOutputsDistributed(this.config.schema, table);
|
|
5272
|
+
const { rows } = await this.db.executeSql(sql, [name, JSON.stringify(payload)]);
|
|
5273
|
+
return {
|
|
5274
|
+
jobs: ids,
|
|
5275
|
+
requested: ids.length,
|
|
5276
|
+
affected: rows.length
|
|
5277
|
+
};
|
|
5278
|
+
}
|
|
5279
|
+
const sql = completeJobsWithOutputs(this.config.schema, table);
|
|
5280
|
+
const result = await this.db.executeSql(sql, [name, JSON.stringify(payload)]);
|
|
5281
|
+
return this.mapCommandResponse(ids, result);
|
|
5282
|
+
}
|
|
5283
|
+
async #failWithOutputs(name, items, forceTerminal = false) {
|
|
5284
|
+
const { table } = await this.getQueueCache(name);
|
|
5285
|
+
const ids = items.map((item) => item.id);
|
|
5286
|
+
if (this.config.noMultiMutationCte) {
|
|
5287
|
+
const outputById = new Map(items.map((item) => [item.id, this.mapCompletionDataArg(item.output)]));
|
|
5288
|
+
return this.withDistributedTransaction(this.db, async (tx) => {
|
|
5289
|
+
const selectQuery = selectJobsToFailById(this.config.schema, table);
|
|
5290
|
+
const { rows: jobs } = await tx.executeSql(selectQuery.text, [name, ids]);
|
|
5291
|
+
if (jobs.length === 0) return {
|
|
5292
|
+
jobs: ids,
|
|
5293
|
+
requested: ids.length,
|
|
5294
|
+
affected: 0
|
|
5295
|
+
};
|
|
5296
|
+
const deleteQuery = deleteJobsToFail(this.config.schema, table);
|
|
5297
|
+
await tx.executeSql(deleteQuery.text, [name, ids]);
|
|
5298
|
+
const count = await this.reinsertFailedJobs(tx, table, jobs, null, outputById, forceTerminal);
|
|
5299
|
+
return {
|
|
5300
|
+
jobs: ids,
|
|
5301
|
+
requested: ids.length,
|
|
5302
|
+
affected: count
|
|
5303
|
+
};
|
|
5304
|
+
});
|
|
5305
|
+
}
|
|
5306
|
+
const payload = items.map((item) => ({
|
|
5307
|
+
id: item.id,
|
|
5308
|
+
output: this.mapCompletionDataArg(item.output)
|
|
5309
|
+
}));
|
|
5310
|
+
const sql = forceTerminal ? deadLetterJobsByIdWithOutputs(this.config.schema, table) : failJobsByIdWithOutputs(this.config.schema, table);
|
|
5311
|
+
const result = await this.db.executeSql(sql, [name, JSON.stringify(payload)]);
|
|
5312
|
+
return this.mapCommandResponse(ids, result);
|
|
5029
5313
|
}
|
|
5030
5314
|
#storeLocalGroupConfig(name, localGroupConcurrency) {
|
|
5031
5315
|
const config = typeof localGroupConcurrency === "number" ? { default: localGroupConcurrency } : localGroupConcurrency;
|
|
@@ -5063,7 +5347,7 @@ var Manager = class extends EventEmitter {
|
|
|
5063
5347
|
#trackLocalGroupEnd(name, groupedJobs) {
|
|
5064
5348
|
for (const job of groupedJobs) if (job.groupId) this.#decrementLocalGroupCount(name, job.groupId);
|
|
5065
5349
|
}
|
|
5066
|
-
async #processJobs(name, jobs, callback, worker, heartbeatRefreshSeconds) {
|
|
5350
|
+
async #processJobs(name, jobs, callback, worker, heartbeatRefreshSeconds, perJobResults = false) {
|
|
5067
5351
|
const jobIds = jobs.map((job) => job.id);
|
|
5068
5352
|
const maxExpiration = jobs.reduce((acc, i) => Math.max(acc, i.expireInSeconds), 0);
|
|
5069
5353
|
const heartbeatSeconds = jobs.reduce((acc, j) => Math.max(acc, j.heartbeatSeconds || 0), 0);
|
|
@@ -5079,21 +5363,34 @@ var Manager = class extends EventEmitter {
|
|
|
5079
5363
|
try {
|
|
5080
5364
|
await this.touch(name, jobIds);
|
|
5081
5365
|
} catch (err) {
|
|
5082
|
-
this.emit(events$
|
|
5366
|
+
this.emit(events$5.error, err);
|
|
5083
5367
|
}
|
|
5084
5368
|
}, intervalMs);
|
|
5085
5369
|
}
|
|
5370
|
+
let completedResult;
|
|
5371
|
+
let completedAffected = 0;
|
|
5372
|
+
let failedError;
|
|
5373
|
+
let didFail = false;
|
|
5086
5374
|
try {
|
|
5087
5375
|
const result = await resolveWithinSeconds(callback(jobs), maxExpiration, `handler execution exceeded ${maxExpiration}s`, ac);
|
|
5088
|
-
await this
|
|
5089
|
-
|
|
5376
|
+
if (perJobResults) await this.#settlePerJob(name, jobs, result);
|
|
5377
|
+
else {
|
|
5378
|
+
const completion = await this.complete(name, jobIds, jobIds.length === 1 ? result : void 0);
|
|
5379
|
+
completedResult = result;
|
|
5380
|
+
completedAffected = completion.affected;
|
|
5381
|
+
}
|
|
5090
5382
|
} catch (err) {
|
|
5091
5383
|
await this.fail(name, jobIds, err);
|
|
5092
|
-
|
|
5384
|
+
failedError = err;
|
|
5385
|
+
didFail = true;
|
|
5093
5386
|
} finally {
|
|
5094
5387
|
if (heartbeatTimer) clearInterval(heartbeatTimer);
|
|
5095
5388
|
if (worker) worker.abortController = null;
|
|
5096
5389
|
}
|
|
5390
|
+
if (this.config.__test__enableSpies && this.#spies.has(name)) {
|
|
5391
|
+
if (didFail) await this.#trackJobsFailed(name, jobs, failedError);
|
|
5392
|
+
else if (!perJobResults) await this.#trackJobsCompleted(name, jobs, completedResult, completedAffected);
|
|
5393
|
+
}
|
|
5097
5394
|
}
|
|
5098
5395
|
async start() {
|
|
5099
5396
|
this.stopped = false;
|
|
@@ -5103,7 +5400,7 @@ var Manager = class extends EventEmitter {
|
|
|
5103
5400
|
if (now - this.wipTs < 2e3) return;
|
|
5104
5401
|
const wip = this.getWipData();
|
|
5105
5402
|
if (wip.some((w) => w.count > 0)) {
|
|
5106
|
-
this.emit(events$
|
|
5403
|
+
this.emit(events$5.wip, wip);
|
|
5107
5404
|
this.wipTs = now;
|
|
5108
5405
|
}
|
|
5109
5406
|
}, 2e3);
|
|
@@ -5118,7 +5415,7 @@ var Manager = class extends EventEmitter {
|
|
|
5118
5415
|
return acc;
|
|
5119
5416
|
}, {});
|
|
5120
5417
|
} catch (error) {
|
|
5121
|
-
emit && this.emit(events$
|
|
5418
|
+
emit && this.emit(events$5.error, {
|
|
5122
5419
|
...error,
|
|
5123
5420
|
message: error.message,
|
|
5124
5421
|
stack: error.stack
|
|
@@ -5153,9 +5450,15 @@ var Manager = class extends EventEmitter {
|
|
|
5153
5450
|
async work(name, ...args) {
|
|
5154
5451
|
const { options, callback } = checkWorkArgs(name, args);
|
|
5155
5452
|
if (this.stopped) throw new Error("Workers are disabled. pg-boss is stopped");
|
|
5156
|
-
const { pollingInterval: interval, batchSize = 1, includeMetadata = false, priority = true, localConcurrency = 1, localGroupConcurrency, groupConcurrency, orderByCreatedOn = true, heartbeatRefreshSeconds, minPriority, maxPriority } = options;
|
|
5453
|
+
const { pollingInterval: interval, notifyPollingInterval: notifyInterval, burstWhenReadyExceeds, burstWhenBatchFull = false, batchSize = 1, includeMetadata = false, priority = true, localConcurrency = 1, localGroupConcurrency, groupConcurrency, orderByCreatedOn = true, heartbeatRefreshSeconds, minPriority, maxPriority, perJobResults = false } = options;
|
|
5157
5454
|
if (localGroupConcurrency != null) this.#storeLocalGroupConfig(name, localGroupConcurrency);
|
|
5158
5455
|
const firstWorkerId = randomUUID({ disableEntropyCache: true });
|
|
5456
|
+
const isNotifyActive = () => !!(this.notifier?.available && this.queues?.[name]?.notify);
|
|
5457
|
+
const getReadyCount = () => this.queues?.[name]?.readyCount ?? 0;
|
|
5458
|
+
const resolveInterval = (lastFetchCount) => {
|
|
5459
|
+
if (lastFetchCount >= batchSize && (burstWhenReadyExceeds !== void 0 && getReadyCount() > burstWhenReadyExceeds || burstWhenBatchFull && batchSize > 1)) return 0;
|
|
5460
|
+
return isNotifyActive() ? notifyInterval : interval;
|
|
5461
|
+
};
|
|
5159
5462
|
const createWorker = (workerId, workId) => {
|
|
5160
5463
|
const fetch = () => {
|
|
5161
5464
|
const ignoreGroups = localGroupConcurrency != null ? this.#getGroupsAtLocalCapacity(name) : void 0;
|
|
@@ -5176,7 +5479,7 @@ var Manager = class extends EventEmitter {
|
|
|
5176
5479
|
this.emitWip(name);
|
|
5177
5480
|
this.#trackJobsActive(name, jobs);
|
|
5178
5481
|
const worker = this.workers.get(workerId);
|
|
5179
|
-
if (localGroupConcurrency == null) await this.#processJobs(name, jobs, callback, worker, heartbeatRefreshSeconds);
|
|
5482
|
+
if (localGroupConcurrency == null) await this.#processJobs(name, jobs, callback, worker, heartbeatRefreshSeconds, perJobResults);
|
|
5180
5483
|
else {
|
|
5181
5484
|
const { allowed, excess, groupedJobs } = this.#trackLocalGroupStart(name, jobs);
|
|
5182
5485
|
if (excess.length > 0) {
|
|
@@ -5184,7 +5487,7 @@ var Manager = class extends EventEmitter {
|
|
|
5184
5487
|
await this.restore(name, excessIds);
|
|
5185
5488
|
}
|
|
5186
5489
|
if (allowed.length > 0) try {
|
|
5187
|
-
await this.#processJobs(name, allowed, callback, worker, heartbeatRefreshSeconds);
|
|
5490
|
+
await this.#processJobs(name, allowed, callback, worker, heartbeatRefreshSeconds, perJobResults);
|
|
5188
5491
|
} finally {
|
|
5189
5492
|
this.#trackLocalGroupEnd(name, groupedJobs);
|
|
5190
5493
|
}
|
|
@@ -5192,7 +5495,7 @@ var Manager = class extends EventEmitter {
|
|
|
5192
5495
|
this.emitWip(name);
|
|
5193
5496
|
};
|
|
5194
5497
|
const onError = (error) => {
|
|
5195
|
-
this.emit(events$
|
|
5498
|
+
this.emit(events$5.error, {
|
|
5196
5499
|
...error,
|
|
5197
5500
|
message: error.message,
|
|
5198
5501
|
stack: error.stack,
|
|
@@ -5205,7 +5508,7 @@ var Manager = class extends EventEmitter {
|
|
|
5205
5508
|
workId,
|
|
5206
5509
|
name,
|
|
5207
5510
|
options,
|
|
5208
|
-
|
|
5511
|
+
resolveInterval,
|
|
5209
5512
|
fetch,
|
|
5210
5513
|
onFetch,
|
|
5211
5514
|
onError
|
|
@@ -5231,7 +5534,7 @@ var Manager = class extends EventEmitter {
|
|
|
5231
5534
|
if (!INTERNAL_QUEUES[name]) {
|
|
5232
5535
|
const now = Date.now();
|
|
5233
5536
|
if (now - this.wipTs > 2e3) {
|
|
5234
|
-
this.emit(events$
|
|
5537
|
+
this.emit(events$5.wip, this.getWipData());
|
|
5235
5538
|
this.wipTs = now;
|
|
5236
5539
|
}
|
|
5237
5540
|
}
|
|
@@ -5267,6 +5570,15 @@ var Manager = class extends EventEmitter {
|
|
|
5267
5570
|
notifyWorker(workerId) {
|
|
5268
5571
|
this.workers.get(workerId)?.notify();
|
|
5269
5572
|
}
|
|
5573
|
+
#notifyEnabled(queueNotify) {
|
|
5574
|
+
return !!queueNotify && !this.config.noListenNotify;
|
|
5575
|
+
}
|
|
5576
|
+
notifyQueue(name) {
|
|
5577
|
+
for (const worker of this.workers.values()) if (worker.name === name) worker.notify();
|
|
5578
|
+
}
|
|
5579
|
+
forceFetchLnWorkers() {
|
|
5580
|
+
for (const worker of this.workers.values()) if (this.queues?.[worker.name]?.notify) worker.notify();
|
|
5581
|
+
}
|
|
5270
5582
|
async subscribe(event, name) {
|
|
5271
5583
|
assert(event, "Missing required argument");
|
|
5272
5584
|
assert(name, "Missing required argument");
|
|
@@ -5349,12 +5661,13 @@ var Manager = class extends EventEmitter {
|
|
|
5349
5661
|
deadLetter
|
|
5350
5662
|
};
|
|
5351
5663
|
const db = wrapper || this.db;
|
|
5352
|
-
const { table, policy } = await this.getQueueCache(name);
|
|
5664
|
+
const { table, policy, notify } = await this.getQueueCache(name);
|
|
5353
5665
|
if (policy === QUEUE_POLICIES.key_strict_fifo && !singletonKey) throw new Error(`${QUEUE_POLICIES.key_strict_fifo} queues require a singletonKey`);
|
|
5354
5666
|
const sql = insertJobs(this.config.schema, {
|
|
5355
5667
|
table,
|
|
5356
5668
|
name,
|
|
5357
|
-
returnId: true
|
|
5669
|
+
returnId: true,
|
|
5670
|
+
notify: this.#notifyEnabled(notify)
|
|
5358
5671
|
});
|
|
5359
5672
|
const { rows: try1 } = await db.executeSql(sql, [JSON.stringify([job])]);
|
|
5360
5673
|
if (try1.length === 1) {
|
|
@@ -5382,7 +5695,7 @@ var Manager = class extends EventEmitter {
|
|
|
5382
5695
|
}
|
|
5383
5696
|
async insert(name, jobs, options = {}) {
|
|
5384
5697
|
assert(Array.isArray(jobs), "jobs argument should be an array");
|
|
5385
|
-
const { table, policy } = await this.getQueueCache(name);
|
|
5698
|
+
const { table, policy, notify } = await this.getQueueCache(name);
|
|
5386
5699
|
if (policy === QUEUE_POLICIES.key_strict_fifo) {
|
|
5387
5700
|
for (const job of jobs) if (!job.singletonKey) throw new Error(`${QUEUE_POLICIES.key_strict_fifo} queues require a singletonKey`);
|
|
5388
5701
|
}
|
|
@@ -5396,7 +5709,8 @@ var Manager = class extends EventEmitter {
|
|
|
5396
5709
|
const sql = insertJobs(this.config.schema, {
|
|
5397
5710
|
table,
|
|
5398
5711
|
name,
|
|
5399
|
-
returnId
|
|
5712
|
+
returnId,
|
|
5713
|
+
notify: this.#notifyEnabled(notify)
|
|
5400
5714
|
});
|
|
5401
5715
|
const { rows } = await db.executeSql(sql, [JSON.stringify(insertPayload)]);
|
|
5402
5716
|
if (rows.length) {
|
|
@@ -5443,7 +5757,7 @@ var Manager = class extends EventEmitter {
|
|
|
5443
5757
|
}
|
|
5444
5758
|
const statements = [];
|
|
5445
5759
|
for (const [queueName, queueJobs] of byQueue) {
|
|
5446
|
-
const { table } = await this.getQueueCache(queueName);
|
|
5760
|
+
const { table, notify } = await this.getQueueCache(queueName);
|
|
5447
5761
|
const insertPayload = queueJobs.map((j) => {
|
|
5448
5762
|
const dependencyCount = dependencyCountByRef.get(j.ref) ?? 0;
|
|
5449
5763
|
return {
|
|
@@ -5470,19 +5784,13 @@ var Manager = class extends EventEmitter {
|
|
|
5470
5784
|
pendingDependencies: dependencyCount || void 0
|
|
5471
5785
|
};
|
|
5472
5786
|
});
|
|
5473
|
-
|
|
5787
|
+
statements.push(insertFlowJobs(this.config.schema, {
|
|
5474
5788
|
table,
|
|
5475
|
-
name: queueName
|
|
5476
|
-
|
|
5477
|
-
|
|
5478
|
-
statements.push(`
|
|
5479
|
-
WITH ins AS (
|
|
5480
|
-
${insertSql}
|
|
5481
|
-
)
|
|
5482
|
-
SELECT 1 / (CASE WHEN (SELECT count(*) FROM ins) = ${insertPayload.length} THEN 1 ELSE 0 END)
|
|
5483
|
-
`);
|
|
5789
|
+
name: queueName
|
|
5790
|
+
}, insertPayload));
|
|
5791
|
+
if (this.#notifyEnabled(notify)) statements.push(notifyQueue(this.config.schema, queueName));
|
|
5484
5792
|
}
|
|
5485
|
-
if (depRows.length > 0) statements.push(insertDependencies(this.config.schema
|
|
5793
|
+
if (depRows.length > 0) statements.push(insertDependencies(this.config.schema, depRows));
|
|
5486
5794
|
const db = options.db ?? this.db;
|
|
5487
5795
|
const sql = options.db ? statements.join(";\n") : transaction(statements);
|
|
5488
5796
|
try {
|
|
@@ -5561,24 +5869,17 @@ var Manager = class extends EventEmitter {
|
|
|
5561
5869
|
return fn(db);
|
|
5562
5870
|
}
|
|
5563
5871
|
async completeDistributed(name, ids, outputData, table, db, includeQueued) {
|
|
5564
|
-
|
|
5565
|
-
|
|
5566
|
-
|
|
5567
|
-
|
|
5568
|
-
|
|
5569
|
-
|
|
5570
|
-
|
|
5571
|
-
|
|
5572
|
-
|
|
5573
|
-
|
|
5574
|
-
|
|
5575
|
-
}
|
|
5576
|
-
return {
|
|
5577
|
-
jobs: ids,
|
|
5578
|
-
requested: ids.length,
|
|
5579
|
-
affected: rows.length
|
|
5580
|
-
};
|
|
5581
|
-
});
|
|
5872
|
+
const sql = completeJobsDistributed(this.config.schema, table, includeQueued);
|
|
5873
|
+
const { rows } = await db.executeSql(sql, [
|
|
5874
|
+
name,
|
|
5875
|
+
ids,
|
|
5876
|
+
outputData
|
|
5877
|
+
]);
|
|
5878
|
+
return {
|
|
5879
|
+
jobs: ids,
|
|
5880
|
+
requested: ids.length,
|
|
5881
|
+
affected: rows.length
|
|
5882
|
+
};
|
|
5582
5883
|
}
|
|
5583
5884
|
async fail(name, id, data, options = {}) {
|
|
5584
5885
|
assertQueueName(name);
|
|
@@ -5622,6 +5923,26 @@ var Manager = class extends EventEmitter {
|
|
|
5622
5923
|
const select = selectJobsToFailByHeartbeat(this.config.schema, table, queues);
|
|
5623
5924
|
return this.expireJobsDistributed(table, select, { value: { message: "job heartbeat timeout" } });
|
|
5624
5925
|
}
|
|
5926
|
+
async resolveFlowJobsDistributed(table, names) {
|
|
5927
|
+
const select = selectBlockingParents(this.config.schema, table, names, this.config.noSkipLocked);
|
|
5928
|
+
return this.withDistributedTransaction(this.db, async (tx) => {
|
|
5929
|
+
const { rows } = await tx.executeSql(select.text, select.values);
|
|
5930
|
+
if (rows.length === 0) return 0;
|
|
5931
|
+
const idsByName = /* @__PURE__ */ new Map();
|
|
5932
|
+
for (const row of rows) {
|
|
5933
|
+
const list = idsByName.get(row.name) || [];
|
|
5934
|
+
list.push(row.id);
|
|
5935
|
+
idsByName.set(row.name, list);
|
|
5936
|
+
}
|
|
5937
|
+
const decrementSql = decrementDependents(this.config.schema);
|
|
5938
|
+
const clearSql = clearBlocking(this.config.schema);
|
|
5939
|
+
for (const [name, ids] of idsByName) {
|
|
5940
|
+
await tx.executeSql(decrementSql, [name, ids]);
|
|
5941
|
+
await tx.executeSql(clearSql, [name, ids]);
|
|
5942
|
+
}
|
|
5943
|
+
return rows.length;
|
|
5944
|
+
});
|
|
5945
|
+
}
|
|
5625
5946
|
async expireJobsDistributed(table, select, outputData) {
|
|
5626
5947
|
return this.withDistributedTransaction(this.db, async (tx) => {
|
|
5627
5948
|
const { rows: jobs } = await tx.executeSql(select.text, []);
|
|
@@ -5632,16 +5953,17 @@ var Manager = class extends EventEmitter {
|
|
|
5632
5953
|
return this.reinsertFailedJobs(tx, table, jobs, outputData);
|
|
5633
5954
|
});
|
|
5634
5955
|
}
|
|
5635
|
-
async reinsertFailedJobs(tx, table, jobs, outputData) {
|
|
5956
|
+
async reinsertFailedJobs(tx, table, jobs, outputData, outputById, forceTerminal = false) {
|
|
5636
5957
|
const insertSql = insertRetryJob(this.config.schema, table);
|
|
5637
5958
|
const dlqSql = insertDeadLetterJob(this.config.schema);
|
|
5638
5959
|
let count = 0;
|
|
5639
5960
|
for (const job of jobs) {
|
|
5961
|
+
const jobOutput = outputById ? outputById.get(job.id) ?? null : outputData;
|
|
5640
5962
|
const retryCount = Number(job.retry_count);
|
|
5641
5963
|
const retryLimit = Number(job.retry_limit);
|
|
5642
5964
|
const retryDelay = Number(job.retry_delay);
|
|
5643
5965
|
const retryDelayMax = job.retry_delay_max != null ? Number(job.retry_delay_max) : null;
|
|
5644
|
-
const canRetry = retryCount < retryLimit;
|
|
5966
|
+
const canRetry = !forceTerminal && retryCount < retryLimit;
|
|
5645
5967
|
let retried = false;
|
|
5646
5968
|
if (canRetry) {
|
|
5647
5969
|
let startAfter = job.start_after;
|
|
@@ -5675,7 +5997,7 @@ var Manager = class extends EventEmitter {
|
|
|
5675
5997
|
null,
|
|
5676
5998
|
job.keep_until,
|
|
5677
5999
|
job.policy,
|
|
5678
|
-
|
|
6000
|
+
jobOutput,
|
|
5679
6001
|
job.dead_letter,
|
|
5680
6002
|
null,
|
|
5681
6003
|
job.heartbeat_seconds,
|
|
@@ -5709,7 +6031,7 @@ var Manager = class extends EventEmitter {
|
|
|
5709
6031
|
/* @__PURE__ */ new Date(),
|
|
5710
6032
|
job.keep_until,
|
|
5711
6033
|
job.policy,
|
|
5712
|
-
|
|
6034
|
+
jobOutput,
|
|
5713
6035
|
job.dead_letter,
|
|
5714
6036
|
null,
|
|
5715
6037
|
job.heartbeat_seconds,
|
|
@@ -5720,7 +6042,7 @@ var Manager = class extends EventEmitter {
|
|
|
5720
6042
|
if (job.dead_letter) await tx.executeSql(dlqSql, [
|
|
5721
6043
|
job.dead_letter,
|
|
5722
6044
|
job.data,
|
|
5723
|
-
|
|
6045
|
+
jobOutput
|
|
5724
6046
|
]);
|
|
5725
6047
|
}
|
|
5726
6048
|
count++;
|
|
@@ -5880,7 +6202,9 @@ var Manager = class extends EventEmitter {
|
|
|
5880
6202
|
return Object.assign(queue, stats || {
|
|
5881
6203
|
deferredCount: 0,
|
|
5882
6204
|
queuedCount: 0,
|
|
6205
|
+
readyCount: 0,
|
|
5883
6206
|
activeCount: 0,
|
|
6207
|
+
failedCount: 0,
|
|
5884
6208
|
totalCount: 0
|
|
5885
6209
|
});
|
|
5886
6210
|
}
|
|
@@ -5943,7 +6267,7 @@ var Manager = class extends EventEmitter {
|
|
|
5943
6267
|
};
|
|
5944
6268
|
//#endregion
|
|
5945
6269
|
//#region ../../src/boss.ts
|
|
5946
|
-
var events$
|
|
6270
|
+
var events$4 = {
|
|
5947
6271
|
error: "error",
|
|
5948
6272
|
warning: "warning"
|
|
5949
6273
|
};
|
|
@@ -5969,7 +6293,7 @@ var Boss = class extends EventEmitter {
|
|
|
5969
6293
|
#db;
|
|
5970
6294
|
#config;
|
|
5971
6295
|
#manager;
|
|
5972
|
-
events = events$
|
|
6296
|
+
events = events$4;
|
|
5973
6297
|
constructor(db, manager, config) {
|
|
5974
6298
|
super();
|
|
5975
6299
|
this.#db = db;
|
|
@@ -6004,8 +6328,8 @@ var Boss = class extends EventEmitter {
|
|
|
6004
6328
|
db: this.#db,
|
|
6005
6329
|
schema: this.#config.schema,
|
|
6006
6330
|
persistWarnings: this.#config.persistWarnings,
|
|
6007
|
-
warningEvent: events$
|
|
6008
|
-
errorEvent: events$
|
|
6331
|
+
warningEvent: events$4.warning,
|
|
6332
|
+
errorEvent: events$4.error
|
|
6009
6333
|
};
|
|
6010
6334
|
}
|
|
6011
6335
|
async #executeQuery(query) {
|
|
@@ -6034,7 +6358,7 @@ var Boss = class extends EventEmitter {
|
|
|
6034
6358
|
!this.#stopped && await this.supervise(queues);
|
|
6035
6359
|
!this.#stopped && await this.#maintainWarnings();
|
|
6036
6360
|
} catch (err) {
|
|
6037
|
-
this.emit(events$
|
|
6361
|
+
this.emit(events$4.error, err);
|
|
6038
6362
|
} finally {
|
|
6039
6363
|
this.#maintaining = false;
|
|
6040
6364
|
}
|
|
@@ -6112,7 +6436,7 @@ var Boss = class extends EventEmitter {
|
|
|
6112
6436
|
};
|
|
6113
6437
|
//#endregion
|
|
6114
6438
|
//#region ../../src/bam.ts
|
|
6115
|
-
var events$
|
|
6439
|
+
var events$3 = {
|
|
6116
6440
|
error: "error",
|
|
6117
6441
|
bam: "bam"
|
|
6118
6442
|
};
|
|
@@ -6122,7 +6446,7 @@ var Bam = class extends EventEmitter {
|
|
|
6122
6446
|
#pollInterval;
|
|
6123
6447
|
#db;
|
|
6124
6448
|
#config;
|
|
6125
|
-
events = events$
|
|
6449
|
+
events = events$3;
|
|
6126
6450
|
constructor(db, config) {
|
|
6127
6451
|
super();
|
|
6128
6452
|
this.#db = db;
|
|
@@ -6158,7 +6482,7 @@ var Bam = class extends EventEmitter {
|
|
|
6158
6482
|
const { rows } = await this.#db.executeSql(sql);
|
|
6159
6483
|
if (rows.length === 1) await this.#processCommands();
|
|
6160
6484
|
} catch (err) {
|
|
6161
|
-
this.emit(events$
|
|
6485
|
+
this.emit(events$3.error, err);
|
|
6162
6486
|
} finally {
|
|
6163
6487
|
this.#working = false;
|
|
6164
6488
|
}
|
|
@@ -6167,7 +6491,7 @@ var Bam = class extends EventEmitter {
|
|
|
6167
6491
|
if (this.#stopped) return;
|
|
6168
6492
|
const entry = await this.#getNextCommand();
|
|
6169
6493
|
if (!entry || this.#stopped) return;
|
|
6170
|
-
this.emit(events$
|
|
6494
|
+
this.emit(events$3.bam, {
|
|
6171
6495
|
id: entry.id,
|
|
6172
6496
|
name: entry.name,
|
|
6173
6497
|
status: "in_progress",
|
|
@@ -6178,7 +6502,7 @@ var Bam = class extends EventEmitter {
|
|
|
6178
6502
|
await this.#db.executeSql(entry.command);
|
|
6179
6503
|
if (this.#stopped) return;
|
|
6180
6504
|
await this.#markCompleted(entry.id);
|
|
6181
|
-
this.emit(events$
|
|
6505
|
+
this.emit(events$3.bam, {
|
|
6182
6506
|
id: entry.id,
|
|
6183
6507
|
name: entry.name,
|
|
6184
6508
|
status: "completed",
|
|
@@ -6188,8 +6512,8 @@ var Bam = class extends EventEmitter {
|
|
|
6188
6512
|
} catch (err) {
|
|
6189
6513
|
if (this.#stopped) return;
|
|
6190
6514
|
await this.#markFailed(entry.id, err);
|
|
6191
|
-
this.emit(events$
|
|
6192
|
-
this.emit(events$
|
|
6515
|
+
this.emit(events$3.error, err);
|
|
6516
|
+
this.emit(events$3.bam, {
|
|
6193
6517
|
id: entry.id,
|
|
6194
6518
|
name: entry.name,
|
|
6195
6519
|
status: "failed",
|
|
@@ -6214,6 +6538,181 @@ var Bam = class extends EventEmitter {
|
|
|
6214
6538
|
}
|
|
6215
6539
|
};
|
|
6216
6540
|
//#endregion
|
|
6541
|
+
//#region ../../src/navigator.ts
|
|
6542
|
+
var events$2 = {
|
|
6543
|
+
error: "error",
|
|
6544
|
+
flow: "flow"
|
|
6545
|
+
};
|
|
6546
|
+
var MAX_BATCHES_PER_PASS = 100;
|
|
6547
|
+
var Navigator = class extends EventEmitter {
|
|
6548
|
+
#stopped;
|
|
6549
|
+
#stopping;
|
|
6550
|
+
#working;
|
|
6551
|
+
#pollInterval;
|
|
6552
|
+
#db;
|
|
6553
|
+
#manager;
|
|
6554
|
+
#config;
|
|
6555
|
+
events = events$2;
|
|
6556
|
+
constructor(db, manager, config) {
|
|
6557
|
+
super();
|
|
6558
|
+
this.#db = db;
|
|
6559
|
+
this.#manager = manager;
|
|
6560
|
+
this.#config = config;
|
|
6561
|
+
this.#stopped = true;
|
|
6562
|
+
this.#stopping = false;
|
|
6563
|
+
this.#working = false;
|
|
6564
|
+
}
|
|
6565
|
+
get working() {
|
|
6566
|
+
return this.#working;
|
|
6567
|
+
}
|
|
6568
|
+
async start() {
|
|
6569
|
+
if (!this.#stopped) return;
|
|
6570
|
+
this.#stopped = false;
|
|
6571
|
+
this.#stopping = false;
|
|
6572
|
+
setImmediate(() => this.#onPoll());
|
|
6573
|
+
this.#pollInterval = setInterval(() => this.#onPoll(), this.#config.flowIntervalSeconds * 1e3);
|
|
6574
|
+
}
|
|
6575
|
+
async stop() {
|
|
6576
|
+
if (this.#stopped) return;
|
|
6577
|
+
this.#stopping = true;
|
|
6578
|
+
this.#stopped = true;
|
|
6579
|
+
if (this.#pollInterval) {
|
|
6580
|
+
clearInterval(this.#pollInterval);
|
|
6581
|
+
this.#pollInterval = void 0;
|
|
6582
|
+
}
|
|
6583
|
+
while (this.#working) await delay(10);
|
|
6584
|
+
}
|
|
6585
|
+
async #onPoll() {
|
|
6586
|
+
if (this.#stopped || this.#working) return;
|
|
6587
|
+
this.#working = true;
|
|
6588
|
+
try {
|
|
6589
|
+
if (this.#config.__test__throw_flow) throw new Error(this.#config.__test__throw_flow);
|
|
6590
|
+
if (this.#config.__test__delay_flow_ms) await delay(this.#config.__test__delay_flow_ms);
|
|
6591
|
+
const gate = trySetFlowTime(this.#config.schema, this.#config.flowIntervalSeconds);
|
|
6592
|
+
const { rows } = await this.#db.executeSql(gate);
|
|
6593
|
+
if (rows.length === 1) await this.#resolve();
|
|
6594
|
+
} catch (err) {
|
|
6595
|
+
this.emit(events$2.error, err);
|
|
6596
|
+
} finally {
|
|
6597
|
+
this.#working = false;
|
|
6598
|
+
}
|
|
6599
|
+
}
|
|
6600
|
+
async resolveNow() {
|
|
6601
|
+
while (this.#working) await delay(10);
|
|
6602
|
+
if (this.#stopping) return;
|
|
6603
|
+
this.#working = true;
|
|
6604
|
+
try {
|
|
6605
|
+
await this.#resolve();
|
|
6606
|
+
} finally {
|
|
6607
|
+
this.#working = false;
|
|
6608
|
+
}
|
|
6609
|
+
}
|
|
6610
|
+
async #resolve() {
|
|
6611
|
+
const queueGroups = (await this.#manager.getQueues()).reduce((acc, q) => {
|
|
6612
|
+
acc[q.table] = acc[q.table] || {
|
|
6613
|
+
table: q.table,
|
|
6614
|
+
names: []
|
|
6615
|
+
};
|
|
6616
|
+
acc[q.table].names.push(q.name);
|
|
6617
|
+
return acc;
|
|
6618
|
+
}, {});
|
|
6619
|
+
for (const group of Object.values(queueGroups)) {
|
|
6620
|
+
if (this.#stopping) return;
|
|
6621
|
+
const { table } = group;
|
|
6622
|
+
const names = [...group.names];
|
|
6623
|
+
while (names.length) {
|
|
6624
|
+
if (this.#stopping) return;
|
|
6625
|
+
const chunk = names.splice(0, 100);
|
|
6626
|
+
let batches = 0;
|
|
6627
|
+
let resolved = 0;
|
|
6628
|
+
do {
|
|
6629
|
+
if (this.#stopping) return;
|
|
6630
|
+
resolved = this.#config.noMultiMutationCte ? await this.#manager.resolveFlowJobsDistributed(table, chunk) : await this.#resolveStandard(table, chunk);
|
|
6631
|
+
if (resolved > 0) this.emit(events$2.flow, {
|
|
6632
|
+
table,
|
|
6633
|
+
resolved
|
|
6634
|
+
});
|
|
6635
|
+
} while (resolved >= 1e3 && ++batches < MAX_BATCHES_PER_PASS && !this.#stopping);
|
|
6636
|
+
}
|
|
6637
|
+
}
|
|
6638
|
+
}
|
|
6639
|
+
async #resolveStandard(table, names) {
|
|
6640
|
+
const query = resolveFlowJobs(this.#config.schema, table, names);
|
|
6641
|
+
const { rows } = await this.#db.executeSql(query.text, query.values);
|
|
6642
|
+
return Number(rows[0]?.resolved ?? 0);
|
|
6643
|
+
}
|
|
6644
|
+
};
|
|
6645
|
+
//#endregion
|
|
6646
|
+
//#region ../../src/notifier.ts
|
|
6647
|
+
var events$1 = {
|
|
6648
|
+
error: "error",
|
|
6649
|
+
warning: "warning"
|
|
6650
|
+
};
|
|
6651
|
+
var WARNING_TYPE = "listen_notify_unavailable";
|
|
6652
|
+
var Notifier = class extends EventEmitter {
|
|
6653
|
+
events = events$1;
|
|
6654
|
+
#db;
|
|
6655
|
+
#manager;
|
|
6656
|
+
#config;
|
|
6657
|
+
#handle = null;
|
|
6658
|
+
#stopped = true;
|
|
6659
|
+
constructor(db, manager, config) {
|
|
6660
|
+
super();
|
|
6661
|
+
this.#db = db;
|
|
6662
|
+
this.#manager = manager;
|
|
6663
|
+
this.#config = config;
|
|
6664
|
+
}
|
|
6665
|
+
get available() {
|
|
6666
|
+
return this.#handle !== null;
|
|
6667
|
+
}
|
|
6668
|
+
async start() {
|
|
6669
|
+
if (!this.#stopped) return;
|
|
6670
|
+
this.#stopped = false;
|
|
6671
|
+
if (this.#config.noListenNotify) {
|
|
6672
|
+
this.emit(events$1.warning, {
|
|
6673
|
+
message: `useListenNotify is not supported on the ${this.#config.backend} backend. Continuing with polling only.`,
|
|
6674
|
+
data: {
|
|
6675
|
+
type: WARNING_TYPE,
|
|
6676
|
+
backend: this.#config.backend
|
|
6677
|
+
}
|
|
6678
|
+
});
|
|
6679
|
+
return;
|
|
6680
|
+
}
|
|
6681
|
+
if (typeof this.#db.listen !== "function") {
|
|
6682
|
+
this.emit(events$1.warning, {
|
|
6683
|
+
message: "useListenNotify is enabled but the database connection does not support LISTEN/NOTIFY. Continuing with polling only.",
|
|
6684
|
+
data: { type: WARNING_TYPE }
|
|
6685
|
+
});
|
|
6686
|
+
return;
|
|
6687
|
+
}
|
|
6688
|
+
try {
|
|
6689
|
+
const { rows } = await this.#db.executeSql(`SELECT ${notifyChannelSql(this.#config.schema)} AS channel`);
|
|
6690
|
+
const channel = rows[0].channel;
|
|
6691
|
+
this.#handle = await this.#db.listen(channel, (payload) => this.#manager.notifyQueue(payload), () => this.#manager.forceFetchLnWorkers());
|
|
6692
|
+
} catch (err) {
|
|
6693
|
+
this.emit(events$1.warning, {
|
|
6694
|
+
message: "Failed to start LISTEN/NOTIFY listener. Continuing with polling only.",
|
|
6695
|
+
data: {
|
|
6696
|
+
type: WARNING_TYPE,
|
|
6697
|
+
error: err?.message
|
|
6698
|
+
}
|
|
6699
|
+
});
|
|
6700
|
+
}
|
|
6701
|
+
}
|
|
6702
|
+
async stop() {
|
|
6703
|
+
if (this.#stopped) return;
|
|
6704
|
+
this.#stopped = true;
|
|
6705
|
+
if (this.#handle) {
|
|
6706
|
+
try {
|
|
6707
|
+
await this.#handle.close();
|
|
6708
|
+
} catch (err) {
|
|
6709
|
+
this.emit(events$1.error, err);
|
|
6710
|
+
}
|
|
6711
|
+
this.#handle = null;
|
|
6712
|
+
}
|
|
6713
|
+
}
|
|
6714
|
+
};
|
|
6715
|
+
//#endregion
|
|
6217
6716
|
//#region ../../src/db.ts
|
|
6218
6717
|
var Db = class extends EventEmitter {
|
|
6219
6718
|
pool;
|
|
@@ -6224,7 +6723,7 @@ var Db = class extends EventEmitter {
|
|
|
6224
6723
|
constructor(config) {
|
|
6225
6724
|
super();
|
|
6226
6725
|
config.application_name = config.application_name || "pgboss";
|
|
6227
|
-
config.connectionTimeoutMillis
|
|
6726
|
+
config.connectionTimeoutMillis ??= 1e4;
|
|
6228
6727
|
this.config = config;
|
|
6229
6728
|
this._pgbdb = true;
|
|
6230
6729
|
this.opened = false;
|
|
@@ -6245,6 +6744,63 @@ var Db = class extends EventEmitter {
|
|
|
6245
6744
|
assert(this.opened, "Database not opened. Call open() before executing SQL.");
|
|
6246
6745
|
return await this.pool.query(text, values);
|
|
6247
6746
|
}
|
|
6747
|
+
async listen(channel, onNotification, onReconnect) {
|
|
6748
|
+
assert(this.opened, "Database not opened. Call open() before listening.");
|
|
6749
|
+
let closed = false;
|
|
6750
|
+
let client = null;
|
|
6751
|
+
let reconnectTimer = null;
|
|
6752
|
+
let attempt = 0;
|
|
6753
|
+
const scheduleReconnect = () => {
|
|
6754
|
+
if (closed || reconnectTimer) return;
|
|
6755
|
+
const backoff = Math.min(3e4, 1e3 * 2 ** Math.min(attempt, 5));
|
|
6756
|
+
attempt++;
|
|
6757
|
+
reconnectTimer = setTimeout(() => {
|
|
6758
|
+
reconnectTimer = null;
|
|
6759
|
+
connect().catch(() => scheduleReconnect());
|
|
6760
|
+
}, backoff);
|
|
6761
|
+
};
|
|
6762
|
+
const connect = async () => {
|
|
6763
|
+
if (closed) return;
|
|
6764
|
+
const next = new pg.Client(this.config);
|
|
6765
|
+
next.on("error", (error) => {
|
|
6766
|
+
this.emit("error", error);
|
|
6767
|
+
if (!closed) {
|
|
6768
|
+
next.removeAllListeners();
|
|
6769
|
+
next.end().catch(() => {});
|
|
6770
|
+
if (client === next) client = null;
|
|
6771
|
+
scheduleReconnect();
|
|
6772
|
+
}
|
|
6773
|
+
});
|
|
6774
|
+
next.on("notification", (msg) => {
|
|
6775
|
+
if (msg.payload !== void 0) onNotification(msg.payload);
|
|
6776
|
+
});
|
|
6777
|
+
client = next;
|
|
6778
|
+
try {
|
|
6779
|
+
await next.connect();
|
|
6780
|
+
await next.query(`LISTEN "${channel}"`);
|
|
6781
|
+
} catch (err) {
|
|
6782
|
+
next.removeAllListeners();
|
|
6783
|
+
await next.end().catch(() => {});
|
|
6784
|
+
if (client === next) client = null;
|
|
6785
|
+
throw err;
|
|
6786
|
+
}
|
|
6787
|
+
attempt = 0;
|
|
6788
|
+
onReconnect();
|
|
6789
|
+
};
|
|
6790
|
+
await connect();
|
|
6791
|
+
return { close: async () => {
|
|
6792
|
+
closed = true;
|
|
6793
|
+
if (reconnectTimer) {
|
|
6794
|
+
clearTimeout(reconnectTimer);
|
|
6795
|
+
reconnectTimer = null;
|
|
6796
|
+
}
|
|
6797
|
+
if (client) {
|
|
6798
|
+
client.removeAllListeners();
|
|
6799
|
+
await client.end().catch(() => {});
|
|
6800
|
+
client = null;
|
|
6801
|
+
}
|
|
6802
|
+
} };
|
|
6803
|
+
}
|
|
6248
6804
|
async withTransaction(fn) {
|
|
6249
6805
|
assert(this.opened, "Database not opened. Call open() before executing SQL.");
|
|
6250
6806
|
const client = await this.pool.connect();
|
|
@@ -6268,7 +6824,8 @@ var events = Object.freeze({
|
|
|
6268
6824
|
warning: "warning",
|
|
6269
6825
|
wip: "wip",
|
|
6270
6826
|
stopped: "stopped",
|
|
6271
|
-
bam: "bam"
|
|
6827
|
+
bam: "bam",
|
|
6828
|
+
flow: "flow"
|
|
6272
6829
|
});
|
|
6273
6830
|
var PgBoss = class extends EventEmitter {
|
|
6274
6831
|
#stoppingOn;
|
|
@@ -6282,6 +6839,8 @@ var PgBoss = class extends EventEmitter {
|
|
|
6282
6839
|
#manager;
|
|
6283
6840
|
#timekeeper;
|
|
6284
6841
|
#bam;
|
|
6842
|
+
#navigator;
|
|
6843
|
+
#notifier;
|
|
6285
6844
|
constructor(value) {
|
|
6286
6845
|
super();
|
|
6287
6846
|
this.#stoppingOn = null;
|
|
@@ -6297,15 +6856,22 @@ var PgBoss = class extends EventEmitter {
|
|
|
6297
6856
|
const timekeeper = new Timekeeper(db, manager, config);
|
|
6298
6857
|
manager.timekeeper = timekeeper;
|
|
6299
6858
|
const bam = new Bam(db, config);
|
|
6859
|
+
const navigator = new Navigator(db, manager, config);
|
|
6860
|
+
const notifier = new Notifier(db, manager, config);
|
|
6861
|
+
manager.notifier = notifier;
|
|
6300
6862
|
this.#promoteEvents(manager);
|
|
6301
6863
|
this.#promoteEvents(boss);
|
|
6302
6864
|
this.#promoteEvents(timekeeper);
|
|
6303
6865
|
this.#promoteEvents(bam);
|
|
6866
|
+
this.#promoteEvents(navigator);
|
|
6867
|
+
this.#promoteEvents(notifier);
|
|
6304
6868
|
this.#boss = boss;
|
|
6305
6869
|
this.#contractor = contractor;
|
|
6306
6870
|
this.#manager = manager;
|
|
6307
6871
|
this.#timekeeper = timekeeper;
|
|
6308
6872
|
this.#bam = bam;
|
|
6873
|
+
this.#navigator = navigator;
|
|
6874
|
+
this.#notifier = notifier;
|
|
6309
6875
|
}
|
|
6310
6876
|
#promoteEvents(emitter) {
|
|
6311
6877
|
for (const event of Object.values(emitter?.events)) emitter.on(event, (arg) => this.emit(event, arg));
|
|
@@ -6319,7 +6885,11 @@ var PgBoss = class extends EventEmitter {
|
|
|
6319
6885
|
if (this.#config.migrate) await this.#contractor.start();
|
|
6320
6886
|
else await this.#contractor.check();
|
|
6321
6887
|
await this.#manager.start();
|
|
6322
|
-
if (this.#config.
|
|
6888
|
+
if (this.#config.useListenNotify) await this.#notifier.start();
|
|
6889
|
+
if (this.#config.supervise) {
|
|
6890
|
+
await this.#boss.start();
|
|
6891
|
+
await this.#navigator.start();
|
|
6892
|
+
}
|
|
6323
6893
|
if (this.#config.schedule) await this.#timekeeper.start();
|
|
6324
6894
|
if (this.#config.migrate) await this.#bam.start();
|
|
6325
6895
|
} catch (err) {
|
|
@@ -6348,9 +6918,11 @@ var PgBoss = class extends EventEmitter {
|
|
|
6348
6918
|
let { close = true, graceful = true, timeout = 3e4 } = options;
|
|
6349
6919
|
timeout = Math.max(timeout, 1e3);
|
|
6350
6920
|
this.#stoppingOn = Date.now();
|
|
6921
|
+
await this.#notifier.stop();
|
|
6351
6922
|
await this.#manager.stop();
|
|
6352
6923
|
await this.#timekeeper.stop();
|
|
6353
6924
|
await this.#boss.stop();
|
|
6925
|
+
await this.#navigator.stop();
|
|
6354
6926
|
await this.#bam.stop();
|
|
6355
6927
|
const shutdown = async () => {
|
|
6356
6928
|
await this.#manager.failWip();
|
|
@@ -6464,7 +7036,7 @@ var PgBoss = class extends EventEmitter {
|
|
|
6464
7036
|
return this.#manager.deleteQueue(name);
|
|
6465
7037
|
}
|
|
6466
7038
|
getQueues(names) {
|
|
6467
|
-
return this.#manager.getQueues();
|
|
7039
|
+
return this.#manager.getQueues(names);
|
|
6468
7040
|
}
|
|
6469
7041
|
getQueue(name) {
|
|
6470
7042
|
return this.#manager.getQueue(name);
|
|
@@ -6478,12 +7050,18 @@ var PgBoss = class extends EventEmitter {
|
|
|
6478
7050
|
isBamWorking() {
|
|
6479
7051
|
return this.#bam.working;
|
|
6480
7052
|
}
|
|
7053
|
+
isResolvingFlow() {
|
|
7054
|
+
return this.#navigator.working;
|
|
7055
|
+
}
|
|
6481
7056
|
isCheckingSkew() {
|
|
6482
7057
|
return this.#timekeeper.checkingSkew;
|
|
6483
7058
|
}
|
|
6484
7059
|
supervise(name) {
|
|
6485
7060
|
return this.#boss.supervise(name);
|
|
6486
7061
|
}
|
|
7062
|
+
resolveFlow() {
|
|
7063
|
+
return this.#navigator.resolveNow();
|
|
7064
|
+
}
|
|
6487
7065
|
getWipData(options) {
|
|
6488
7066
|
return this.#manager.getWipData(options);
|
|
6489
7067
|
}
|
|
@@ -6514,7 +7092,7 @@ var PgBoss = class extends EventEmitter {
|
|
|
6514
7092
|
return rows;
|
|
6515
7093
|
}
|
|
6516
7094
|
async getBamEntries() {
|
|
6517
|
-
const sql = getBamEntries(this.#config.schema);
|
|
7095
|
+
const sql = getBamEntries$1(this.#config.schema);
|
|
6518
7096
|
const { rows } = await this.#db.executeSql(sql);
|
|
6519
7097
|
return rows;
|
|
6520
7098
|
}
|
|
@@ -6609,7 +7187,9 @@ var QUEUE_COLUMNS = `
|
|
|
6609
7187
|
deletion_seconds as "deleteAfterSeconds",
|
|
6610
7188
|
deferred_count as "deferredCount",
|
|
6611
7189
|
queued_count as "queuedCount",
|
|
7190
|
+
GREATEST(queued_count - deferred_count, 0) as "readyCount",
|
|
6612
7191
|
active_count as "activeCount",
|
|
7192
|
+
failed_count as "failedCount",
|
|
6613
7193
|
total_count as "totalCount",
|
|
6614
7194
|
warning_queued as "warningQueueSize",
|
|
6615
7195
|
singletons_active as "singletonsActive",
|
|
@@ -6862,19 +7442,81 @@ async function getWarningCount(dbUrl, schema, type) {
|
|
|
6862
7442
|
throw err;
|
|
6863
7443
|
}
|
|
6864
7444
|
}
|
|
7445
|
+
async function getBamEntries(dbUrl, schema, options = {}) {
|
|
7446
|
+
const s = validateIdentifier(schema);
|
|
7447
|
+
const { status = null, limit = 200, offset = 0 } = options;
|
|
7448
|
+
const sql = `
|
|
7449
|
+
SELECT
|
|
7450
|
+
id,
|
|
7451
|
+
name,
|
|
7452
|
+
version,
|
|
7453
|
+
status,
|
|
7454
|
+
queue,
|
|
7455
|
+
table_name as "table",
|
|
7456
|
+
command,
|
|
7457
|
+
error,
|
|
7458
|
+
created_on as "createdOn",
|
|
7459
|
+
started_on as "startedOn",
|
|
7460
|
+
completed_on as "completedOn"
|
|
7461
|
+
FROM ${s}.bam
|
|
7462
|
+
WHERE ($1::text IS NULL OR status = $1)
|
|
7463
|
+
ORDER BY version DESC, created_on DESC
|
|
7464
|
+
LIMIT $2 OFFSET $3
|
|
7465
|
+
`;
|
|
7466
|
+
try {
|
|
7467
|
+
return await query(dbUrl, sql, [
|
|
7468
|
+
status,
|
|
7469
|
+
limit,
|
|
7470
|
+
offset
|
|
7471
|
+
]);
|
|
7472
|
+
} catch (err) {
|
|
7473
|
+
if (err && typeof err === "object" && "code" in err && err.code === "42P01") return [];
|
|
7474
|
+
throw err;
|
|
7475
|
+
}
|
|
7476
|
+
}
|
|
7477
|
+
async function getBamCount(dbUrl, schema, status) {
|
|
7478
|
+
const sql = `
|
|
7479
|
+
SELECT COUNT(*)::int as count
|
|
7480
|
+
FROM ${validateIdentifier(schema)}.bam
|
|
7481
|
+
WHERE ($1::text IS NULL OR status = $1)
|
|
7482
|
+
`;
|
|
7483
|
+
try {
|
|
7484
|
+
return (await queryOne(dbUrl, sql, [status ?? null]))?.count ?? 0;
|
|
7485
|
+
} catch (err) {
|
|
7486
|
+
if (err && typeof err === "object" && "code" in err && err.code === "42P01") return 0;
|
|
7487
|
+
throw err;
|
|
7488
|
+
}
|
|
7489
|
+
}
|
|
7490
|
+
async function getBamStatusSummary(dbUrl, schema) {
|
|
7491
|
+
const sql = `
|
|
7492
|
+
SELECT status, count(*)::int as count, max(created_on) as "lastCreatedOn"
|
|
7493
|
+
FROM ${validateIdentifier(schema)}.bam
|
|
7494
|
+
GROUP BY status
|
|
7495
|
+
`;
|
|
7496
|
+
try {
|
|
7497
|
+
return await query(dbUrl, sql);
|
|
7498
|
+
} catch (err) {
|
|
7499
|
+
if (err && typeof err === "object" && "code" in err && err.code === "42P01") return [];
|
|
7500
|
+
throw err;
|
|
7501
|
+
}
|
|
7502
|
+
}
|
|
6865
7503
|
async function getQueueStats(dbUrl, schema) {
|
|
6866
7504
|
return await queryOne(dbUrl, `
|
|
6867
7505
|
SELECT
|
|
6868
7506
|
COALESCE(SUM(deferred_count), 0)::int as "totalDeferred",
|
|
6869
7507
|
COALESCE(SUM(queued_count), 0)::int as "totalQueued",
|
|
7508
|
+
COALESCE(SUM(GREATEST(queued_count - deferred_count, 0)), 0)::int as "totalReady",
|
|
6870
7509
|
COALESCE(SUM(active_count), 0)::int as "totalActive",
|
|
7510
|
+
COALESCE(SUM(failed_count), 0)::int as "totalFailed",
|
|
6871
7511
|
COALESCE(SUM(total_count), 0)::int as "totalJobs",
|
|
6872
7512
|
COUNT(*)::int as "queueCount"
|
|
6873
7513
|
FROM ${validateIdentifier(schema)}.queue
|
|
6874
7514
|
`) ?? {
|
|
6875
7515
|
totalDeferred: 0,
|
|
6876
7516
|
totalQueued: 0,
|
|
7517
|
+
totalReady: 0,
|
|
6877
7518
|
totalActive: 0,
|
|
7519
|
+
totalFailed: 0,
|
|
6878
7520
|
totalJobs: 0,
|
|
6879
7521
|
queueCount: 0
|
|
6880
7522
|
};
|
|
@@ -6975,9 +7617,21 @@ var statCards = [
|
|
|
6975
7617
|
{
|
|
6976
7618
|
name: "Queued Jobs",
|
|
6977
7619
|
key: "totalQueued",
|
|
6978
|
-
hint: "
|
|
7620
|
+
hint: "incl. deferred",
|
|
7621
|
+
accent: "neutral"
|
|
7622
|
+
},
|
|
7623
|
+
{
|
|
7624
|
+
name: "Deferred",
|
|
7625
|
+
key: "totalDeferred",
|
|
7626
|
+
hint: "scheduled for later",
|
|
6979
7627
|
accent: "neutral"
|
|
6980
7628
|
},
|
|
7629
|
+
{
|
|
7630
|
+
name: "Ready",
|
|
7631
|
+
key: "totalReady",
|
|
7632
|
+
hint: "ready to process",
|
|
7633
|
+
accent: "primary"
|
|
7634
|
+
},
|
|
6981
7635
|
{
|
|
6982
7636
|
name: "Active",
|
|
6983
7637
|
key: "totalActive",
|
|
@@ -6985,9 +7639,9 @@ var statCards = [
|
|
|
6985
7639
|
accent: "primary"
|
|
6986
7640
|
},
|
|
6987
7641
|
{
|
|
6988
|
-
name: "
|
|
6989
|
-
key: "
|
|
6990
|
-
hint: "
|
|
7642
|
+
name: "Failed",
|
|
7643
|
+
key: "totalFailed",
|
|
7644
|
+
hint: "recent failures",
|
|
6991
7645
|
accent: "neutral"
|
|
6992
7646
|
},
|
|
6993
7647
|
{
|
|
@@ -7199,34 +7853,45 @@ function ErrorCard({ title, message = "Please check your database connection and
|
|
|
7199
7853
|
//#endregion
|
|
7200
7854
|
//#region app/routes/_index.tsx
|
|
7201
7855
|
var _index_exports = /* @__PURE__ */ __exportAll({
|
|
7202
|
-
ErrorBoundary: () => ErrorBoundary$
|
|
7856
|
+
ErrorBoundary: () => ErrorBoundary$11,
|
|
7203
7857
|
default: () => _index_default,
|
|
7204
|
-
loader: () => loader$
|
|
7858
|
+
loader: () => loader$11
|
|
7205
7859
|
});
|
|
7206
|
-
async function loader$
|
|
7860
|
+
async function loader$11({ context }) {
|
|
7207
7861
|
const { DB_URL, SCHEMA } = context.get(dbContext);
|
|
7208
|
-
const [warnings, stats, topQueues, totalQueues, problemQueuesCount] = await Promise.all([
|
|
7862
|
+
const [warnings, stats, topQueues, totalQueues, problemQueuesCount, bamSummary] = await Promise.all([
|
|
7209
7863
|
getWarnings(DB_URL, SCHEMA, { limit: 5 }),
|
|
7210
7864
|
getQueueStats(DB_URL, SCHEMA),
|
|
7211
7865
|
getTopQueues(DB_URL, SCHEMA, 5),
|
|
7212
7866
|
getQueueCount(DB_URL, SCHEMA),
|
|
7213
|
-
getProblemQueuesCount(DB_URL, SCHEMA)
|
|
7867
|
+
getProblemQueuesCount(DB_URL, SCHEMA),
|
|
7868
|
+
getBamStatusSummary(DB_URL, SCHEMA)
|
|
7214
7869
|
]);
|
|
7215
7870
|
return {
|
|
7216
7871
|
stats,
|
|
7217
7872
|
warnings,
|
|
7218
7873
|
topQueues,
|
|
7874
|
+
migrations: bamSummary.reduce((acc, row) => {
|
|
7875
|
+
if (row.status === "pending") acc.pending += row.count;
|
|
7876
|
+
else if (row.status === "in_progress") acc.inProgress += row.count;
|
|
7877
|
+
else if (row.status === "failed") acc.failed += row.count;
|
|
7878
|
+
return acc;
|
|
7879
|
+
}, {
|
|
7880
|
+
pending: 0,
|
|
7881
|
+
inProgress: 0,
|
|
7882
|
+
failed: 0
|
|
7883
|
+
}),
|
|
7219
7884
|
queueStats: {
|
|
7220
7885
|
totalQueues,
|
|
7221
7886
|
problemQueues: problemQueuesCount
|
|
7222
7887
|
}
|
|
7223
7888
|
};
|
|
7224
7889
|
}
|
|
7225
|
-
var ErrorBoundary$
|
|
7890
|
+
var ErrorBoundary$11 = UNSAFE_withErrorBoundaryProps(function ErrorBoundary() {
|
|
7226
7891
|
return /* @__PURE__ */ jsx(ErrorCard, { title: "Failed to load dashboard" });
|
|
7227
7892
|
});
|
|
7228
7893
|
var _index_default = UNSAFE_withComponentProps(function Overview({ loaderData }) {
|
|
7229
|
-
const { stats, warnings, topQueues } = loaderData;
|
|
7894
|
+
const { stats, warnings, topQueues, migrations } = loaderData;
|
|
7230
7895
|
return /* @__PURE__ */ jsxs("div", { children: [
|
|
7231
7896
|
/* @__PURE__ */ jsx(PageHeader, {
|
|
7232
7897
|
title: "Overview",
|
|
@@ -7241,9 +7906,10 @@ var _index_default = UNSAFE_withComponentProps(function Overview({ loaderData })
|
|
|
7241
7906
|
})
|
|
7242
7907
|
}),
|
|
7243
7908
|
/* @__PURE__ */ jsx("div", {
|
|
7244
|
-
className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-
|
|
7909
|
+
className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-6 mb-4",
|
|
7245
7910
|
children: /* @__PURE__ */ jsx(StatsCards, { stats })
|
|
7246
7911
|
}),
|
|
7912
|
+
/* @__PURE__ */ jsx(MigrationsBanner, { migrations }),
|
|
7247
7913
|
/* @__PURE__ */ jsxs("div", {
|
|
7248
7914
|
className: "grid grid-cols-1 lg:grid-cols-[1.5fr_1fr] gap-4",
|
|
7249
7915
|
children: [/* @__PURE__ */ jsxs(Card, { children: [/* @__PURE__ */ jsxs(CardHeader, { children: [/* @__PURE__ */ jsx(CardTitle, { children: "Top Queues" }), /* @__PURE__ */ jsx(DbLink, {
|
|
@@ -7312,6 +7978,37 @@ var _index_default = UNSAFE_withComponentProps(function Overview({ loaderData })
|
|
|
7312
7978
|
})
|
|
7313
7979
|
] });
|
|
7314
7980
|
});
|
|
7981
|
+
function MigrationsBanner({ migrations }) {
|
|
7982
|
+
const { pending, inProgress, failed } = migrations;
|
|
7983
|
+
if (pending === 0 && inProgress === 0 && failed === 0) return null;
|
|
7984
|
+
const parts = [];
|
|
7985
|
+
if (pending > 0) parts.push(`${pending.toLocaleString()} pending`);
|
|
7986
|
+
if (inProgress > 0) parts.push(`${inProgress.toLocaleString()} in progress`);
|
|
7987
|
+
if (failed > 0) parts.push(`${failed.toLocaleString()} failed`);
|
|
7988
|
+
return /* @__PURE__ */ jsx(DbLink, {
|
|
7989
|
+
to: "/migrations",
|
|
7990
|
+
className: "block mb-4",
|
|
7991
|
+
children: /* @__PURE__ */ jsxs(Card, {
|
|
7992
|
+
className: "flex items-center gap-3 px-4 py-3 hover:bg-[var(--surface-hover)]",
|
|
7993
|
+
children: [
|
|
7994
|
+
/* @__PURE__ */ jsx(Badge, {
|
|
7995
|
+
variant: failed > 0 ? "error" : "warning",
|
|
7996
|
+
size: "sm",
|
|
7997
|
+
dot: true,
|
|
7998
|
+
children: "Async migrations"
|
|
7999
|
+
}),
|
|
8000
|
+
/* @__PURE__ */ jsx("span", {
|
|
8001
|
+
className: "text-sm text-[var(--text-secondary)]",
|
|
8002
|
+
children: parts.join(" · ")
|
|
8003
|
+
}),
|
|
8004
|
+
/* @__PURE__ */ jsx("span", {
|
|
8005
|
+
className: "ml-auto text-sm font-medium text-primary-600 dark:text-primary-400",
|
|
8006
|
+
children: "View"
|
|
8007
|
+
})
|
|
8008
|
+
]
|
|
8009
|
+
})
|
|
8010
|
+
});
|
|
8011
|
+
}
|
|
7315
8012
|
function QueueStatusBadge({ queue }) {
|
|
7316
8013
|
if ((queue.warningQueueSize ?? 0) > 0 && queue.queuedCount > (queue.warningQueueSize ?? 0)) return /* @__PURE__ */ jsx(Badge, {
|
|
7317
8014
|
variant: "error",
|
|
@@ -7826,10 +8523,10 @@ function SearchIcon$1({ className }) {
|
|
|
7826
8523
|
//#endregion
|
|
7827
8524
|
//#region app/routes/jobs.tsx
|
|
7828
8525
|
var jobs_exports = /* @__PURE__ */ __exportAll({
|
|
7829
|
-
ErrorBoundary: () => ErrorBoundary$
|
|
8526
|
+
ErrorBoundary: () => ErrorBoundary$10,
|
|
7830
8527
|
buildSearchParams: () => buildSearchParams,
|
|
7831
8528
|
default: () => jobs_default,
|
|
7832
|
-
loader: () => loader$
|
|
8529
|
+
loader: () => loader$10,
|
|
7833
8530
|
parseFiltersFromUrl: () => parseFiltersFromUrl
|
|
7834
8531
|
});
|
|
7835
8532
|
function parseFiltersFromUrl(searchParams) {
|
|
@@ -7866,7 +8563,7 @@ function parseFiltersFromUrl(searchParams) {
|
|
|
7866
8563
|
shouldRunCount
|
|
7867
8564
|
};
|
|
7868
8565
|
}
|
|
7869
|
-
async function loader$
|
|
8566
|
+
async function loader$10({ request, context }) {
|
|
7870
8567
|
const { DB_URL, SCHEMA } = context.get(dbContext);
|
|
7871
8568
|
const url = new URL(request.url);
|
|
7872
8569
|
const parsed = parseFiltersFromUrl(url.searchParams);
|
|
@@ -7914,7 +8611,7 @@ async function loader$9({ request, context }) {
|
|
|
7914
8611
|
hasPrevPage
|
|
7915
8612
|
};
|
|
7916
8613
|
}
|
|
7917
|
-
var ErrorBoundary$
|
|
8614
|
+
var ErrorBoundary$10 = UNSAFE_withErrorBoundaryProps(function ErrorBoundary() {
|
|
7918
8615
|
return /* @__PURE__ */ jsx(ErrorCard, { title: "Failed to load jobs" });
|
|
7919
8616
|
});
|
|
7920
8617
|
function buildSearchParams(filters) {
|
|
@@ -8094,11 +8791,11 @@ function Chip({ label, onRemove }) {
|
|
|
8094
8791
|
//#endregion
|
|
8095
8792
|
//#region app/routes/queues._index.tsx
|
|
8096
8793
|
var queues__index_exports = /* @__PURE__ */ __exportAll({
|
|
8097
|
-
ErrorBoundary: () => ErrorBoundary$
|
|
8794
|
+
ErrorBoundary: () => ErrorBoundary$9,
|
|
8098
8795
|
default: () => queues__index_default,
|
|
8099
|
-
loader: () => loader$
|
|
8796
|
+
loader: () => loader$9
|
|
8100
8797
|
});
|
|
8101
|
-
async function loader$
|
|
8798
|
+
async function loader$9({ request, context }) {
|
|
8102
8799
|
const { DB_URL, SCHEMA } = context.get(dbContext);
|
|
8103
8800
|
const url = new URL(request.url);
|
|
8104
8801
|
const page = parsePageNumber(url.searchParams.get("page"));
|
|
@@ -8131,7 +8828,7 @@ async function loader$8({ request, context }) {
|
|
|
8131
8828
|
search
|
|
8132
8829
|
};
|
|
8133
8830
|
}
|
|
8134
|
-
var ErrorBoundary$
|
|
8831
|
+
var ErrorBoundary$9 = UNSAFE_withErrorBoundaryProps(function ErrorBoundary() {
|
|
8135
8832
|
return /* @__PURE__ */ jsx("div", {
|
|
8136
8833
|
className: "p-6",
|
|
8137
8834
|
children: /* @__PURE__ */ jsx(Card, { children: /* @__PURE__ */ jsxs(CardContent, {
|
|
@@ -8297,13 +8994,21 @@ var queues__index_default = UNSAFE_withComponentProps(function QueuesIndex({ loa
|
|
|
8297
8994
|
className: "text-right",
|
|
8298
8995
|
children: "Queued"
|
|
8299
8996
|
}),
|
|
8997
|
+
/* @__PURE__ */ jsx(TableHead, {
|
|
8998
|
+
className: "text-right",
|
|
8999
|
+
children: "Deferred"
|
|
9000
|
+
}),
|
|
9001
|
+
/* @__PURE__ */ jsx(TableHead, {
|
|
9002
|
+
className: "text-right",
|
|
9003
|
+
children: "Ready"
|
|
9004
|
+
}),
|
|
8300
9005
|
/* @__PURE__ */ jsx(TableHead, {
|
|
8301
9006
|
className: "text-right",
|
|
8302
9007
|
children: "Active"
|
|
8303
9008
|
}),
|
|
8304
9009
|
/* @__PURE__ */ jsx(TableHead, {
|
|
8305
9010
|
className: "text-right",
|
|
8306
|
-
children: "
|
|
9011
|
+
children: "Failed"
|
|
8307
9012
|
}),
|
|
8308
9013
|
/* @__PURE__ */ jsx(TableHead, {
|
|
8309
9014
|
className: "text-right",
|
|
@@ -8313,7 +9018,7 @@ var queues__index_default = UNSAFE_withComponentProps(function QueuesIndex({ loa
|
|
|
8313
9018
|
/* @__PURE__ */ jsx(TableHead, { children: "Status" })
|
|
8314
9019
|
] }) }), /* @__PURE__ */ jsx(TableBody, { children: queues.length === 0 ? /* @__PURE__ */ jsx(TableRow, { children: /* @__PURE__ */ jsx(TableCell, {
|
|
8315
9020
|
className: "text-center text-[var(--text-tertiary)] py-8",
|
|
8316
|
-
colSpan:
|
|
9021
|
+
colSpan: 11,
|
|
8317
9022
|
children: "No queues found"
|
|
8318
9023
|
}) }) : queues.map((queue) => {
|
|
8319
9024
|
const hasBacklog = (queue.warningQueueSize ?? 0) > 0 && queue.queuedCount > (queue.warningQueueSize ?? 0);
|
|
@@ -8336,13 +9041,21 @@ var queues__index_default = UNSAFE_withComponentProps(function QueuesIndex({ loa
|
|
|
8336
9041
|
className: "text-right pgb-num text-[var(--text-primary)]",
|
|
8337
9042
|
children: queue.queuedCount.toLocaleString()
|
|
8338
9043
|
}),
|
|
9044
|
+
/* @__PURE__ */ jsx(TableCell, {
|
|
9045
|
+
className: "text-right pgb-num text-[var(--text-primary)]",
|
|
9046
|
+
children: queue.deferredCount.toLocaleString()
|
|
9047
|
+
}),
|
|
9048
|
+
/* @__PURE__ */ jsx(TableCell, {
|
|
9049
|
+
className: "text-right pgb-num text-[var(--text-primary)]",
|
|
9050
|
+
children: queue.readyCount.toLocaleString()
|
|
9051
|
+
}),
|
|
8339
9052
|
/* @__PURE__ */ jsx(TableCell, {
|
|
8340
9053
|
className: "text-right pgb-num text-[var(--text-primary)]",
|
|
8341
9054
|
children: queue.activeCount.toLocaleString()
|
|
8342
9055
|
}),
|
|
8343
9056
|
/* @__PURE__ */ jsx(TableCell, {
|
|
8344
9057
|
className: "text-right pgb-num text-[var(--text-primary)]",
|
|
8345
|
-
children: queue.
|
|
9058
|
+
children: queue.failedCount.toLocaleString()
|
|
8346
9059
|
}),
|
|
8347
9060
|
/* @__PURE__ */ jsx(TableCell, {
|
|
8348
9061
|
className: "text-right pgb-num text-[var(--text-primary)]",
|
|
@@ -8520,12 +9233,12 @@ var SelectContent = ({ children }) => /* @__PURE__ */ jsx(Fragment, { children }
|
|
|
8520
9233
|
//#endregion
|
|
8521
9234
|
//#region app/routes/queues.create.tsx
|
|
8522
9235
|
var queues_create_exports = /* @__PURE__ */ __exportAll({
|
|
8523
|
-
ErrorBoundary: () => ErrorBoundary$
|
|
9236
|
+
ErrorBoundary: () => ErrorBoundary$8,
|
|
8524
9237
|
action: () => action$5,
|
|
8525
9238
|
default: () => queues_create_default,
|
|
8526
|
-
loader: () => loader$
|
|
9239
|
+
loader: () => loader$8
|
|
8527
9240
|
});
|
|
8528
|
-
async function loader$
|
|
9241
|
+
async function loader$8({ context }) {
|
|
8529
9242
|
const { DB_URL, SCHEMA } = context.get(dbContext);
|
|
8530
9243
|
return { queues: await getQueues(DB_URL, SCHEMA) };
|
|
8531
9244
|
}
|
|
@@ -8593,7 +9306,7 @@ async function action$5({ request, context }) {
|
|
|
8593
9306
|
const dbParam = new URL(request.url).searchParams.get("db");
|
|
8594
9307
|
return redirect(dbParam ? `/queues/${encodeURIComponent(queueName.trim())}?db=${encodeURIComponent(dbParam)}` : `/queues/${encodeURIComponent(queueName.trim())}`);
|
|
8595
9308
|
}
|
|
8596
|
-
var ErrorBoundary$
|
|
9309
|
+
var ErrorBoundary$8 = UNSAFE_withErrorBoundaryProps(function ErrorBoundary() {
|
|
8597
9310
|
return /* @__PURE__ */ jsx(ErrorCard, {
|
|
8598
9311
|
title: "Failed to load queue creation page",
|
|
8599
9312
|
backTo: {
|
|
@@ -9041,12 +9754,12 @@ DialogDescription.displayName = "DialogDescription";
|
|
|
9041
9754
|
//#endregion
|
|
9042
9755
|
//#region app/routes/queues.$name.tsx
|
|
9043
9756
|
var queues_$name_exports = /* @__PURE__ */ __exportAll({
|
|
9044
|
-
ErrorBoundary: () => ErrorBoundary$
|
|
9757
|
+
ErrorBoundary: () => ErrorBoundary$7,
|
|
9045
9758
|
action: () => action$4,
|
|
9046
9759
|
default: () => queues_$name_default,
|
|
9047
|
-
loader: () => loader$
|
|
9760
|
+
loader: () => loader$7
|
|
9048
9761
|
});
|
|
9049
|
-
async function loader$
|
|
9762
|
+
async function loader$7({ params, request, context }) {
|
|
9050
9763
|
const { DB_URL, SCHEMA } = context.get(dbContext);
|
|
9051
9764
|
const url = new URL(request.url);
|
|
9052
9765
|
const stateParam = url.searchParams.get("state");
|
|
@@ -9119,7 +9832,7 @@ async function action$4({ params, request, context }) {
|
|
|
9119
9832
|
message
|
|
9120
9833
|
};
|
|
9121
9834
|
}
|
|
9122
|
-
var ErrorBoundary$
|
|
9835
|
+
var ErrorBoundary$7 = UNSAFE_withErrorBoundaryProps(function ErrorBoundary() {
|
|
9123
9836
|
return /* @__PURE__ */ jsx(ErrorCard, {
|
|
9124
9837
|
title: "Failed to load queue",
|
|
9125
9838
|
backTo: {
|
|
@@ -9178,13 +9891,23 @@ var queues_$name_default = UNSAFE_withComponentProps(function QueueDetail({ load
|
|
|
9178
9891
|
]
|
|
9179
9892
|
}),
|
|
9180
9893
|
/* @__PURE__ */ jsxs("div", {
|
|
9181
|
-
className: "grid grid-cols-2 sm:grid-cols-
|
|
9894
|
+
className: "grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-6 gap-4",
|
|
9182
9895
|
children: [
|
|
9183
9896
|
/* @__PURE__ */ jsx(StatCard, {
|
|
9184
9897
|
label: "Queued",
|
|
9185
9898
|
value: queue.queuedCount.toLocaleString(),
|
|
9186
9899
|
accent: overThreshold ? "error" : "neutral",
|
|
9187
|
-
hint: overThreshold ? "over threshold" : "
|
|
9900
|
+
hint: overThreshold ? "over threshold" : "incl. deferred"
|
|
9901
|
+
}),
|
|
9902
|
+
/* @__PURE__ */ jsx(StatCard, {
|
|
9903
|
+
label: "Deferred",
|
|
9904
|
+
value: queue.deferredCount.toLocaleString()
|
|
9905
|
+
}),
|
|
9906
|
+
/* @__PURE__ */ jsx(StatCard, {
|
|
9907
|
+
label: "Ready",
|
|
9908
|
+
value: queue.readyCount.toLocaleString(),
|
|
9909
|
+
accent: "primary",
|
|
9910
|
+
hint: "ready to process"
|
|
9188
9911
|
}),
|
|
9189
9912
|
/* @__PURE__ */ jsx(StatCard, {
|
|
9190
9913
|
label: "Active",
|
|
@@ -9192,8 +9915,9 @@ var queues_$name_default = UNSAFE_withComponentProps(function QueueDetail({ load
|
|
|
9192
9915
|
accent: "primary"
|
|
9193
9916
|
}),
|
|
9194
9917
|
/* @__PURE__ */ jsx(StatCard, {
|
|
9195
|
-
label: "
|
|
9196
|
-
value: queue.
|
|
9918
|
+
label: "Failed",
|
|
9919
|
+
value: queue.failedCount.toLocaleString(),
|
|
9920
|
+
hint: "recent failures"
|
|
9197
9921
|
}),
|
|
9198
9922
|
/* @__PURE__ */ jsx(StatCard, {
|
|
9199
9923
|
label: "Total",
|
|
@@ -9539,12 +10263,12 @@ function ConfirmDialog({ title, description, confirmLabel, confirmVariant = "pri
|
|
|
9539
10263
|
//#endregion
|
|
9540
10264
|
//#region app/routes/queues.$name.jobs.$jobId.tsx
|
|
9541
10265
|
var queues_$name_jobs_$jobId_exports = /* @__PURE__ */ __exportAll({
|
|
9542
|
-
ErrorBoundary: () => ErrorBoundary$
|
|
10266
|
+
ErrorBoundary: () => ErrorBoundary$6,
|
|
9543
10267
|
action: () => action$3,
|
|
9544
10268
|
default: () => queues_$name_jobs_$jobId_default,
|
|
9545
|
-
loader: () => loader$
|
|
10269
|
+
loader: () => loader$6
|
|
9546
10270
|
});
|
|
9547
|
-
async function loader$
|
|
10271
|
+
async function loader$6({ params, context }) {
|
|
9548
10272
|
const { DB_URL, SCHEMA } = context.get(dbContext);
|
|
9549
10273
|
const job = await getJobById(DB_URL, SCHEMA, params.name, params.jobId);
|
|
9550
10274
|
if (!job) throw new Response("Job not found", { status: 404 });
|
|
@@ -9598,7 +10322,7 @@ async function action$3({ params, request, context }) {
|
|
|
9598
10322
|
message
|
|
9599
10323
|
};
|
|
9600
10324
|
}
|
|
9601
|
-
var ErrorBoundary$
|
|
10325
|
+
var ErrorBoundary$6 = UNSAFE_withErrorBoundaryProps(function ErrorBoundary() {
|
|
9602
10326
|
return /* @__PURE__ */ jsx(ErrorCard, {
|
|
9603
10327
|
title: "Failed to load job",
|
|
9604
10328
|
backTo: {
|
|
@@ -9851,11 +10575,11 @@ function ConfigItem({ label, value, mono = false }) {
|
|
|
9851
10575
|
//#endregion
|
|
9852
10576
|
//#region app/routes/schedules.tsx
|
|
9853
10577
|
var schedules_exports = /* @__PURE__ */ __exportAll({
|
|
9854
|
-
ErrorBoundary: () => ErrorBoundary$
|
|
10578
|
+
ErrorBoundary: () => ErrorBoundary$5,
|
|
9855
10579
|
default: () => schedules_default,
|
|
9856
|
-
loader: () => loader$
|
|
10580
|
+
loader: () => loader$5
|
|
9857
10581
|
});
|
|
9858
|
-
async function loader$
|
|
10582
|
+
async function loader$5({ request, context }) {
|
|
9859
10583
|
const { DB_URL, SCHEMA } = context.get(dbContext);
|
|
9860
10584
|
const page = parsePageNumber(new URL(request.url).searchParams.get("page"));
|
|
9861
10585
|
const limit = 20;
|
|
@@ -9873,7 +10597,7 @@ async function loader$4({ request, context }) {
|
|
|
9873
10597
|
hasPrevPage: page > 1
|
|
9874
10598
|
};
|
|
9875
10599
|
}
|
|
9876
|
-
var ErrorBoundary$
|
|
10600
|
+
var ErrorBoundary$5 = UNSAFE_withErrorBoundaryProps(function ErrorBoundary() {
|
|
9877
10601
|
return /* @__PURE__ */ jsx(ErrorCard, { title: "Failed to load schedules" });
|
|
9878
10602
|
});
|
|
9879
10603
|
function cronHuman(cron) {
|
|
@@ -9983,12 +10707,12 @@ var schedules_default = UNSAFE_withComponentProps(function Schedules({ loaderDat
|
|
|
9983
10707
|
//#endregion
|
|
9984
10708
|
//#region app/routes/schedules.$name.$key.tsx
|
|
9985
10709
|
var schedules_$name_$key_exports = /* @__PURE__ */ __exportAll({
|
|
9986
|
-
ErrorBoundary: () => ErrorBoundary$
|
|
10710
|
+
ErrorBoundary: () => ErrorBoundary$4,
|
|
9987
10711
|
action: () => action$2,
|
|
9988
10712
|
default: () => schedules_$name_$key_default,
|
|
9989
|
-
loader: () => loader$
|
|
10713
|
+
loader: () => loader$4
|
|
9990
10714
|
});
|
|
9991
|
-
async function loader$
|
|
10715
|
+
async function loader$4({ params, context }) {
|
|
9992
10716
|
const { DB_URL, SCHEMA } = context.get(dbContext);
|
|
9993
10717
|
const key = params.key === "__default__" ? "" : params.key;
|
|
9994
10718
|
const schedule = await getSchedule(DB_URL, SCHEMA, params.name, key);
|
|
@@ -10006,7 +10730,7 @@ async function action$2({ params, request, context }) {
|
|
|
10006
10730
|
}
|
|
10007
10731
|
return { error: "Invalid action" };
|
|
10008
10732
|
}
|
|
10009
|
-
var ErrorBoundary$
|
|
10733
|
+
var ErrorBoundary$4 = UNSAFE_withErrorBoundaryProps(function ErrorBoundary() {
|
|
10010
10734
|
return /* @__PURE__ */ jsx(ErrorCard, {
|
|
10011
10735
|
title: "Failed to load schedule",
|
|
10012
10736
|
backTo: {
|
|
@@ -10166,12 +10890,12 @@ var schedules_$name_$key_default = UNSAFE_withComponentProps(function ScheduleDe
|
|
|
10166
10890
|
//#endregion
|
|
10167
10891
|
//#region app/routes/schedules.new.tsx
|
|
10168
10892
|
var schedules_new_exports = /* @__PURE__ */ __exportAll({
|
|
10169
|
-
ErrorBoundary: () => ErrorBoundary$
|
|
10893
|
+
ErrorBoundary: () => ErrorBoundary$3,
|
|
10170
10894
|
action: () => action$1,
|
|
10171
10895
|
default: () => schedules_new_default,
|
|
10172
|
-
loader: () => loader$
|
|
10896
|
+
loader: () => loader$3
|
|
10173
10897
|
});
|
|
10174
|
-
async function loader$
|
|
10898
|
+
async function loader$3({ context }) {
|
|
10175
10899
|
const { DB_URL, SCHEMA } = context.get(dbContext);
|
|
10176
10900
|
return { queues: await getQueues(DB_URL, SCHEMA) };
|
|
10177
10901
|
}
|
|
@@ -10224,7 +10948,7 @@ async function action$1({ request, context }) {
|
|
|
10224
10948
|
const dbParam = new URL(request.url).searchParams.get("db");
|
|
10225
10949
|
return redirect(dbParam ? `/schedules?db=${encodeURIComponent(dbParam)}` : `/schedules`);
|
|
10226
10950
|
}
|
|
10227
|
-
var ErrorBoundary$
|
|
10951
|
+
var ErrorBoundary$3 = UNSAFE_withErrorBoundaryProps(function ErrorBoundary() {
|
|
10228
10952
|
return /* @__PURE__ */ jsx(ErrorCard, {
|
|
10229
10953
|
title: "Failed to load schedule creation",
|
|
10230
10954
|
backTo: {
|
|
@@ -10490,12 +11214,12 @@ var schedules_new_default = UNSAFE_withComponentProps(function CreateSchedule({
|
|
|
10490
11214
|
//#endregion
|
|
10491
11215
|
//#region app/routes/send.tsx
|
|
10492
11216
|
var send_exports = /* @__PURE__ */ __exportAll({
|
|
10493
|
-
ErrorBoundary: () => ErrorBoundary$
|
|
11217
|
+
ErrorBoundary: () => ErrorBoundary$2,
|
|
10494
11218
|
action: () => action,
|
|
10495
11219
|
default: () => send_default,
|
|
10496
|
-
loader: () => loader$
|
|
11220
|
+
loader: () => loader$2
|
|
10497
11221
|
});
|
|
10498
|
-
async function loader$
|
|
11222
|
+
async function loader$2({ context }) {
|
|
10499
11223
|
const { DB_URL, SCHEMA } = context.get(dbContext);
|
|
10500
11224
|
return { queues: await getQueues(DB_URL, SCHEMA) };
|
|
10501
11225
|
}
|
|
@@ -10545,7 +11269,7 @@ async function action({ request, context }) {
|
|
|
10545
11269
|
const dbParam = new URL(request.url).searchParams.get("db");
|
|
10546
11270
|
return redirect(dbParam ? `/queues/${encodeURIComponent(queueName.trim())}?db=${encodeURIComponent(dbParam)}` : `/queues/${encodeURIComponent(queueName.trim())}`);
|
|
10547
11271
|
}
|
|
10548
|
-
var ErrorBoundary$
|
|
11272
|
+
var ErrorBoundary$2 = UNSAFE_withErrorBoundaryProps(function ErrorBoundary() {
|
|
10549
11273
|
return /* @__PURE__ */ jsx(ErrorCard, {
|
|
10550
11274
|
title: "Failed to load job sending page",
|
|
10551
11275
|
backTo: {
|
|
@@ -10777,6 +11501,182 @@ var send_default = UNSAFE_withComponentProps(function SendJob({ loaderData }) {
|
|
|
10777
11501
|
});
|
|
10778
11502
|
});
|
|
10779
11503
|
//#endregion
|
|
11504
|
+
//#region app/routes/migrations.tsx
|
|
11505
|
+
var migrations_exports = /* @__PURE__ */ __exportAll({
|
|
11506
|
+
ErrorBoundary: () => ErrorBoundary$1,
|
|
11507
|
+
default: () => migrations_default,
|
|
11508
|
+
loader: () => loader$1
|
|
11509
|
+
});
|
|
11510
|
+
var PAGE_SIZE = 50;
|
|
11511
|
+
var STATUS_ACCENT = {
|
|
11512
|
+
pending: "warning",
|
|
11513
|
+
in_progress: "primary",
|
|
11514
|
+
completed: "success",
|
|
11515
|
+
failed: "error"
|
|
11516
|
+
};
|
|
11517
|
+
async function loader$1({ request, context }) {
|
|
11518
|
+
const { DB_URL, SCHEMA } = context.get(dbContext);
|
|
11519
|
+
const url = new URL(request.url);
|
|
11520
|
+
const statusParam = url.searchParams.get("status");
|
|
11521
|
+
const statusFilter = isValidBamStatus(statusParam) ? statusParam : null;
|
|
11522
|
+
const page = parsePageNumber(url.searchParams.get("page"));
|
|
11523
|
+
const offset = (page - 1) * PAGE_SIZE;
|
|
11524
|
+
const [entries, totalCount, summary] = await Promise.all([
|
|
11525
|
+
getBamEntries(DB_URL, SCHEMA, {
|
|
11526
|
+
status: statusFilter,
|
|
11527
|
+
limit: PAGE_SIZE,
|
|
11528
|
+
offset
|
|
11529
|
+
}),
|
|
11530
|
+
getBamCount(DB_URL, SCHEMA, statusFilter),
|
|
11531
|
+
getBamStatusSummary(DB_URL, SCHEMA)
|
|
11532
|
+
]);
|
|
11533
|
+
return {
|
|
11534
|
+
entries,
|
|
11535
|
+
summary,
|
|
11536
|
+
statusFilter,
|
|
11537
|
+
page,
|
|
11538
|
+
totalPages: Math.ceil(totalCount / PAGE_SIZE)
|
|
11539
|
+
};
|
|
11540
|
+
}
|
|
11541
|
+
var ErrorBoundary$1 = UNSAFE_withErrorBoundaryProps(function ErrorBoundary() {
|
|
11542
|
+
return /* @__PURE__ */ jsx(ErrorCard, {
|
|
11543
|
+
title: "Failed to load migrations",
|
|
11544
|
+
backTo: {
|
|
11545
|
+
href: "/",
|
|
11546
|
+
label: "Back to Dashboard"
|
|
11547
|
+
}
|
|
11548
|
+
});
|
|
11549
|
+
});
|
|
11550
|
+
var migrations_default = UNSAFE_withComponentProps(function Migrations({ loaderData }) {
|
|
11551
|
+
const { entries, summary, statusFilter, page, totalPages } = loaderData;
|
|
11552
|
+
const [searchParams, setSearchParams] = useSearchParams();
|
|
11553
|
+
const counts = countByStatus(summary);
|
|
11554
|
+
const handleFilterChange = (key, value) => {
|
|
11555
|
+
const params = new URLSearchParams(searchParams);
|
|
11556
|
+
if (value) params.set(key, value);
|
|
11557
|
+
else params.delete(key);
|
|
11558
|
+
params.delete("page");
|
|
11559
|
+
setSearchParams(params);
|
|
11560
|
+
};
|
|
11561
|
+
const handlePageChange = (newPage) => {
|
|
11562
|
+
const params = new URLSearchParams(searchParams);
|
|
11563
|
+
params.set("page", newPage.toString());
|
|
11564
|
+
setSearchParams(params);
|
|
11565
|
+
};
|
|
11566
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
11567
|
+
className: "space-y-4",
|
|
11568
|
+
children: [
|
|
11569
|
+
/* @__PURE__ */ jsx(PageHeader, {
|
|
11570
|
+
title: "Migrations",
|
|
11571
|
+
subtitle: "Background async migrations (BAM) — schema changes such as concurrent index builds that run outside the install transaction"
|
|
11572
|
+
}),
|
|
11573
|
+
/* @__PURE__ */ jsx("div", {
|
|
11574
|
+
className: "grid grid-cols-2 gap-4 lg:grid-cols-4",
|
|
11575
|
+
children: BAM_STATUSES.map((status) => /* @__PURE__ */ jsx(StatCard, {
|
|
11576
|
+
label: BAM_STATUS_LABELS[status],
|
|
11577
|
+
value: counts[status].toLocaleString(),
|
|
11578
|
+
accent: counts[status] > 0 ? STATUS_ACCENT[status] : "neutral"
|
|
11579
|
+
}, status))
|
|
11580
|
+
}),
|
|
11581
|
+
/* @__PURE__ */ jsxs(Card, { children: [
|
|
11582
|
+
/* @__PURE__ */ jsxs(CardHeader, { children: [/* @__PURE__ */ jsx(CardTitle, { children: "Migration commands" }), /* @__PURE__ */ jsx(FilterSelect, {
|
|
11583
|
+
value: statusFilter,
|
|
11584
|
+
options: BAM_STATUS_OPTIONS,
|
|
11585
|
+
onChange: (value) => handleFilterChange("status", value)
|
|
11586
|
+
})] }),
|
|
11587
|
+
/* @__PURE__ */ jsx(CardContent, {
|
|
11588
|
+
className: "p-0",
|
|
11589
|
+
children: /* @__PURE__ */ jsxs(Table, { children: [/* @__PURE__ */ jsx(TableHeader, { children: /* @__PURE__ */ jsxs(TableRow, { children: [
|
|
11590
|
+
/* @__PURE__ */ jsx(TableHead, { children: "Name" }),
|
|
11591
|
+
/* @__PURE__ */ jsx(TableHead, {
|
|
11592
|
+
className: "text-right",
|
|
11593
|
+
children: "Ver"
|
|
11594
|
+
}),
|
|
11595
|
+
/* @__PURE__ */ jsx(TableHead, { children: "Status" }),
|
|
11596
|
+
/* @__PURE__ */ jsx(TableHead, { children: "Table" }),
|
|
11597
|
+
/* @__PURE__ */ jsx(TableHead, { children: "Created" }),
|
|
11598
|
+
/* @__PURE__ */ jsx(TableHead, { children: "Started" }),
|
|
11599
|
+
/* @__PURE__ */ jsx(TableHead, { children: "Completed" }),
|
|
11600
|
+
/* @__PURE__ */ jsx(TableHead, { children: "Command / Error" })
|
|
11601
|
+
] }) }), /* @__PURE__ */ jsx(TableBody, { children: entries.length === 0 ? /* @__PURE__ */ jsx(TableRow, { children: /* @__PURE__ */ jsx(TableCell, {
|
|
11602
|
+
className: "text-center text-[var(--text-tertiary)] py-8",
|
|
11603
|
+
colSpan: 8,
|
|
11604
|
+
children: statusFilter ? `No ${BAM_STATUS_LABELS[statusFilter].toLowerCase()} migrations found` : "No async migrations recorded."
|
|
11605
|
+
}) }) : entries.map((entry) => /* @__PURE__ */ jsxs(TableRow, { children: [
|
|
11606
|
+
/* @__PURE__ */ jsx(TableCell, {
|
|
11607
|
+
className: "text-[var(--text-primary)] font-medium",
|
|
11608
|
+
children: entry.name
|
|
11609
|
+
}),
|
|
11610
|
+
/* @__PURE__ */ jsx(TableCell, {
|
|
11611
|
+
className: "text-right pgb-num text-[var(--text-tertiary)]",
|
|
11612
|
+
children: entry.version
|
|
11613
|
+
}),
|
|
11614
|
+
/* @__PURE__ */ jsx(TableCell, { children: /* @__PURE__ */ jsx(Badge, {
|
|
11615
|
+
variant: BAM_STATUS_VARIANTS[entry.status],
|
|
11616
|
+
size: "sm",
|
|
11617
|
+
dot: true,
|
|
11618
|
+
children: BAM_STATUS_LABELS[entry.status]
|
|
11619
|
+
}) }),
|
|
11620
|
+
/* @__PURE__ */ jsxs(TableCell, {
|
|
11621
|
+
className: "font-mono text-xs text-[var(--text-secondary)] whitespace-nowrap",
|
|
11622
|
+
children: [entry.table, entry.queue ? /* @__PURE__ */ jsxs("span", {
|
|
11623
|
+
className: "text-[var(--text-tertiary)]",
|
|
11624
|
+
children: [" · ", entry.queue]
|
|
11625
|
+
}) : null]
|
|
11626
|
+
}),
|
|
11627
|
+
/* @__PURE__ */ jsx(TableCell, {
|
|
11628
|
+
className: "pgb-num text-[var(--text-tertiary)] whitespace-nowrap",
|
|
11629
|
+
children: formatTimestamp(entry.createdOn)
|
|
11630
|
+
}),
|
|
11631
|
+
/* @__PURE__ */ jsx(TableCell, {
|
|
11632
|
+
className: "pgb-num text-[var(--text-tertiary)] whitespace-nowrap",
|
|
11633
|
+
children: formatTimestamp(entry.startedOn)
|
|
11634
|
+
}),
|
|
11635
|
+
/* @__PURE__ */ jsx(TableCell, {
|
|
11636
|
+
className: "pgb-num text-[var(--text-tertiary)] whitespace-nowrap",
|
|
11637
|
+
children: formatTimestamp(entry.completedOn)
|
|
11638
|
+
}),
|
|
11639
|
+
/* @__PURE__ */ jsxs(TableCell, {
|
|
11640
|
+
className: "max-w-md",
|
|
11641
|
+
children: [entry.error ? /* @__PURE__ */ jsx("p", {
|
|
11642
|
+
className: "mb-1 font-mono text-xs text-[var(--error-600)] break-words whitespace-pre-wrap",
|
|
11643
|
+
children: entry.error
|
|
11644
|
+
}) : null, /* @__PURE__ */ jsxs("details", { children: [/* @__PURE__ */ jsx("summary", {
|
|
11645
|
+
className: "cursor-pointer text-xs text-[var(--text-tertiary)] select-none",
|
|
11646
|
+
children: "View command"
|
|
11647
|
+
}), /* @__PURE__ */ jsx("pre", {
|
|
11648
|
+
className: "mt-1 overflow-x-auto rounded bg-[var(--surface-sunken)] p-2 font-mono text-xs text-[var(--text-secondary)] whitespace-pre-wrap",
|
|
11649
|
+
children: entry.command
|
|
11650
|
+
})] })]
|
|
11651
|
+
})
|
|
11652
|
+
] }, entry.id)) })] })
|
|
11653
|
+
}),
|
|
11654
|
+
/* @__PURE__ */ jsx(Pagination, {
|
|
11655
|
+
page,
|
|
11656
|
+
totalPages,
|
|
11657
|
+
hasNextPage: page < totalPages,
|
|
11658
|
+
hasPrevPage: page > 1,
|
|
11659
|
+
onPageChange: handlePageChange
|
|
11660
|
+
})
|
|
11661
|
+
] })
|
|
11662
|
+
]
|
|
11663
|
+
});
|
|
11664
|
+
});
|
|
11665
|
+
function formatTimestamp(value) {
|
|
11666
|
+
if (!value) return "—";
|
|
11667
|
+
return formatDateWithSeconds(new Date(value));
|
|
11668
|
+
}
|
|
11669
|
+
function countByStatus(summary) {
|
|
11670
|
+
const counts = {
|
|
11671
|
+
pending: 0,
|
|
11672
|
+
in_progress: 0,
|
|
11673
|
+
completed: 0,
|
|
11674
|
+
failed: 0
|
|
11675
|
+
};
|
|
11676
|
+
for (const row of summary) if (row.status in counts) counts[row.status] += row.count;
|
|
11677
|
+
return counts;
|
|
11678
|
+
}
|
|
11679
|
+
//#endregion
|
|
10780
11680
|
//#region app/routes/warnings.tsx
|
|
10781
11681
|
var warnings_exports = /* @__PURE__ */ __exportAll({
|
|
10782
11682
|
ErrorBoundary: () => ErrorBoundary,
|
|
@@ -10888,8 +11788,8 @@ function WarningTypeBadge({ type }) {
|
|
|
10888
11788
|
//#region \0virtual:react-router/server-manifest
|
|
10889
11789
|
var server_manifest_default = {
|
|
10890
11790
|
"entry": {
|
|
10891
|
-
"module": "/assets/entry.client-
|
|
10892
|
-
"imports": ["/assets/jsx-runtime-
|
|
11791
|
+
"module": "/assets/entry.client-CqyjuPDB.js",
|
|
11792
|
+
"imports": ["/assets/jsx-runtime-RQyiN6Nr.js", "/assets/react-dom-D_m_Zgd3.js"],
|
|
10893
11793
|
"css": []
|
|
10894
11794
|
},
|
|
10895
11795
|
"routes": {
|
|
@@ -10906,16 +11806,16 @@ var server_manifest_default = {
|
|
|
10906
11806
|
"hasClientMiddleware": false,
|
|
10907
11807
|
"hasDefaultExport": true,
|
|
10908
11808
|
"hasErrorBoundary": true,
|
|
10909
|
-
"module": "/assets/root-
|
|
11809
|
+
"module": "/assets/root-qxoeL6W3.js",
|
|
10910
11810
|
"imports": [
|
|
10911
|
-
"/assets/jsx-runtime-
|
|
10912
|
-
"/assets/react-dom-
|
|
10913
|
-
"/assets/db-link-
|
|
10914
|
-
"/assets/
|
|
10915
|
-
"/assets/
|
|
10916
|
-
"/assets/useOpenInteractionType-
|
|
11811
|
+
"/assets/jsx-runtime-RQyiN6Nr.js",
|
|
11812
|
+
"/assets/react-dom-D_m_Zgd3.js",
|
|
11813
|
+
"/assets/db-link-BajQ1v8I.js",
|
|
11814
|
+
"/assets/createLucideIcon-C-LI4enx.js",
|
|
11815
|
+
"/assets/MenuTrigger-BNvpjhsQ.js",
|
|
11816
|
+
"/assets/useOpenInteractionType-BQ1arb0B.js"
|
|
10917
11817
|
],
|
|
10918
|
-
"css": ["/assets/root-
|
|
11818
|
+
"css": ["/assets/root-B0MB8jZH.css"],
|
|
10919
11819
|
"clientActionModule": void 0,
|
|
10920
11820
|
"clientLoaderModule": void 0,
|
|
10921
11821
|
"clientMiddlewareModule": void 0,
|
|
@@ -10934,15 +11834,15 @@ var server_manifest_default = {
|
|
|
10934
11834
|
"hasClientMiddleware": false,
|
|
10935
11835
|
"hasDefaultExport": true,
|
|
10936
11836
|
"hasErrorBoundary": true,
|
|
10937
|
-
"module": "/assets/_index-
|
|
11837
|
+
"module": "/assets/_index-DqpFaaQw.js",
|
|
10938
11838
|
"imports": [
|
|
10939
|
-
"/assets/jsx-runtime-
|
|
10940
|
-
"/assets/db-link-
|
|
10941
|
-
"/assets/
|
|
10942
|
-
"/assets/
|
|
10943
|
-
"/assets/
|
|
10944
|
-
"/assets/
|
|
10945
|
-
"/assets/
|
|
11839
|
+
"/assets/jsx-runtime-RQyiN6Nr.js",
|
|
11840
|
+
"/assets/db-link-BajQ1v8I.js",
|
|
11841
|
+
"/assets/stat-card-dyg1wY5p.js",
|
|
11842
|
+
"/assets/button-9NpSS9Ow.js",
|
|
11843
|
+
"/assets/badge-CMnQO7Lq.js",
|
|
11844
|
+
"/assets/table-Cz7ujmH_.js",
|
|
11845
|
+
"/assets/error-card-BH7i86fH.js"
|
|
10946
11846
|
],
|
|
10947
11847
|
"css": [],
|
|
10948
11848
|
"clientActionModule": void 0,
|
|
@@ -10963,24 +11863,24 @@ var server_manifest_default = {
|
|
|
10963
11863
|
"hasClientMiddleware": false,
|
|
10964
11864
|
"hasDefaultExport": true,
|
|
10965
11865
|
"hasErrorBoundary": true,
|
|
10966
|
-
"module": "/assets/jobs-
|
|
11866
|
+
"module": "/assets/jobs-CAd_qqLH.js",
|
|
10967
11867
|
"imports": [
|
|
10968
|
-
"/assets/jsx-runtime-
|
|
10969
|
-
"/assets/db-link-
|
|
10970
|
-
"/assets/
|
|
10971
|
-
"/assets/
|
|
10972
|
-
"/assets/
|
|
10973
|
-
"/assets/
|
|
10974
|
-
"/assets/
|
|
10975
|
-
"/assets/
|
|
10976
|
-
"/assets/
|
|
10977
|
-
"/assets/
|
|
10978
|
-
"/assets/
|
|
10979
|
-
"/assets/
|
|
10980
|
-
"/assets/
|
|
10981
|
-
"/assets/
|
|
10982
|
-
"/assets/
|
|
10983
|
-
"/assets/react-dom-
|
|
11868
|
+
"/assets/jsx-runtime-RQyiN6Nr.js",
|
|
11869
|
+
"/assets/db-link-BajQ1v8I.js",
|
|
11870
|
+
"/assets/createLucideIcon-C-LI4enx.js",
|
|
11871
|
+
"/assets/check-7jwc5sb1.js",
|
|
11872
|
+
"/assets/chevron-down-BFFjfYD4.js",
|
|
11873
|
+
"/assets/chevron-right-DGk5QFJF.js",
|
|
11874
|
+
"/assets/x-AhXI_F1j.js",
|
|
11875
|
+
"/assets/MenuTrigger-BNvpjhsQ.js",
|
|
11876
|
+
"/assets/useOpenInteractionType-BQ1arb0B.js",
|
|
11877
|
+
"/assets/button-9NpSS9Ow.js",
|
|
11878
|
+
"/assets/badge-CMnQO7Lq.js",
|
|
11879
|
+
"/assets/table-Cz7ujmH_.js",
|
|
11880
|
+
"/assets/error-card-BH7i86fH.js",
|
|
11881
|
+
"/assets/pagination-C-ohiBmY.js",
|
|
11882
|
+
"/assets/filter-select-Bn_oSiip.js",
|
|
11883
|
+
"/assets/react-dom-D_m_Zgd3.js"
|
|
10984
11884
|
],
|
|
10985
11885
|
"css": [],
|
|
10986
11886
|
"clientActionModule": void 0,
|
|
@@ -11001,14 +11901,14 @@ var server_manifest_default = {
|
|
|
11001
11901
|
"hasClientMiddleware": false,
|
|
11002
11902
|
"hasDefaultExport": true,
|
|
11003
11903
|
"hasErrorBoundary": true,
|
|
11004
|
-
"module": "/assets/queues._index-
|
|
11904
|
+
"module": "/assets/queues._index-8YriSqbQ.js",
|
|
11005
11905
|
"imports": [
|
|
11006
|
-
"/assets/jsx-runtime-
|
|
11007
|
-
"/assets/db-link-
|
|
11008
|
-
"/assets/
|
|
11009
|
-
"/assets/
|
|
11010
|
-
"/assets/
|
|
11011
|
-
"/assets/
|
|
11906
|
+
"/assets/jsx-runtime-RQyiN6Nr.js",
|
|
11907
|
+
"/assets/db-link-BajQ1v8I.js",
|
|
11908
|
+
"/assets/button-9NpSS9Ow.js",
|
|
11909
|
+
"/assets/badge-CMnQO7Lq.js",
|
|
11910
|
+
"/assets/table-Cz7ujmH_.js",
|
|
11911
|
+
"/assets/filter-select-Bn_oSiip.js"
|
|
11012
11912
|
],
|
|
11013
11913
|
"css": [],
|
|
11014
11914
|
"clientActionModule": void 0,
|
|
@@ -11029,14 +11929,14 @@ var server_manifest_default = {
|
|
|
11029
11929
|
"hasClientMiddleware": false,
|
|
11030
11930
|
"hasDefaultExport": true,
|
|
11031
11931
|
"hasErrorBoundary": true,
|
|
11032
|
-
"module": "/assets/queues.create-
|
|
11932
|
+
"module": "/assets/queues.create-DsY0Sc19.js",
|
|
11033
11933
|
"imports": [
|
|
11034
|
-
"/assets/jsx-runtime-
|
|
11035
|
-
"/assets/db-link-
|
|
11036
|
-
"/assets/
|
|
11037
|
-
"/assets/button-
|
|
11038
|
-
"/assets/
|
|
11039
|
-
"/assets/createLucideIcon-
|
|
11934
|
+
"/assets/jsx-runtime-RQyiN6Nr.js",
|
|
11935
|
+
"/assets/db-link-BajQ1v8I.js",
|
|
11936
|
+
"/assets/chevron-down-BFFjfYD4.js",
|
|
11937
|
+
"/assets/button-9NpSS9Ow.js",
|
|
11938
|
+
"/assets/error-card-BH7i86fH.js",
|
|
11939
|
+
"/assets/createLucideIcon-C-LI4enx.js"
|
|
11040
11940
|
],
|
|
11041
11941
|
"css": [],
|
|
11042
11942
|
"clientActionModule": void 0,
|
|
@@ -11057,25 +11957,25 @@ var server_manifest_default = {
|
|
|
11057
11957
|
"hasClientMiddleware": false,
|
|
11058
11958
|
"hasDefaultExport": true,
|
|
11059
11959
|
"hasErrorBoundary": true,
|
|
11060
|
-
"module": "/assets/queues._name-
|
|
11960
|
+
"module": "/assets/queues._name-Cb17IB2u.js",
|
|
11061
11961
|
"imports": [
|
|
11062
|
-
"/assets/jsx-runtime-
|
|
11063
|
-
"/assets/db-link-
|
|
11064
|
-
"/assets/
|
|
11065
|
-
"/assets/
|
|
11066
|
-
"/assets/
|
|
11067
|
-
"/assets/
|
|
11068
|
-
"/assets/
|
|
11069
|
-
"/assets/
|
|
11070
|
-
"/assets/
|
|
11071
|
-
"/assets/
|
|
11072
|
-
"/assets/
|
|
11073
|
-
"/assets/
|
|
11074
|
-
"/assets/
|
|
11075
|
-
"/assets/
|
|
11076
|
-
"/assets/
|
|
11077
|
-
"/assets/
|
|
11078
|
-
"/assets/
|
|
11962
|
+
"/assets/jsx-runtime-RQyiN6Nr.js",
|
|
11963
|
+
"/assets/db-link-BajQ1v8I.js",
|
|
11964
|
+
"/assets/createLucideIcon-C-LI4enx.js",
|
|
11965
|
+
"/assets/chevron-down-BFFjfYD4.js",
|
|
11966
|
+
"/assets/chevron-right-DGk5QFJF.js",
|
|
11967
|
+
"/assets/MenuTrigger-BNvpjhsQ.js",
|
|
11968
|
+
"/assets/dialog-D-oczDM2.js",
|
|
11969
|
+
"/assets/stat-card-dyg1wY5p.js",
|
|
11970
|
+
"/assets/button-9NpSS9Ow.js",
|
|
11971
|
+
"/assets/badge-CMnQO7Lq.js",
|
|
11972
|
+
"/assets/table-Cz7ujmH_.js",
|
|
11973
|
+
"/assets/error-card-BH7i86fH.js",
|
|
11974
|
+
"/assets/pagination-C-ohiBmY.js",
|
|
11975
|
+
"/assets/filter-select-Bn_oSiip.js",
|
|
11976
|
+
"/assets/react-dom-D_m_Zgd3.js",
|
|
11977
|
+
"/assets/useOpenInteractionType-BQ1arb0B.js",
|
|
11978
|
+
"/assets/x-AhXI_F1j.js"
|
|
11079
11979
|
],
|
|
11080
11980
|
"css": [],
|
|
11081
11981
|
"clientActionModule": void 0,
|
|
@@ -11096,19 +11996,19 @@ var server_manifest_default = {
|
|
|
11096
11996
|
"hasClientMiddleware": false,
|
|
11097
11997
|
"hasDefaultExport": true,
|
|
11098
11998
|
"hasErrorBoundary": true,
|
|
11099
|
-
"module": "/assets/queues._name.jobs._jobId-
|
|
11999
|
+
"module": "/assets/queues._name.jobs._jobId-Bkv8POBj.js",
|
|
11100
12000
|
"imports": [
|
|
11101
|
-
"/assets/jsx-runtime-
|
|
11102
|
-
"/assets/db-link-
|
|
11103
|
-
"/assets/
|
|
11104
|
-
"/assets/
|
|
11105
|
-
"/assets/
|
|
11106
|
-
"/assets/
|
|
11107
|
-
"/assets/
|
|
11108
|
-
"/assets/
|
|
11109
|
-
"/assets/
|
|
11110
|
-
"/assets/
|
|
11111
|
-
"/assets/react-dom-
|
|
12001
|
+
"/assets/jsx-runtime-RQyiN6Nr.js",
|
|
12002
|
+
"/assets/db-link-BajQ1v8I.js",
|
|
12003
|
+
"/assets/createLucideIcon-C-LI4enx.js",
|
|
12004
|
+
"/assets/check-7jwc5sb1.js",
|
|
12005
|
+
"/assets/dialog-D-oczDM2.js",
|
|
12006
|
+
"/assets/button-9NpSS9Ow.js",
|
|
12007
|
+
"/assets/badge-CMnQO7Lq.js",
|
|
12008
|
+
"/assets/error-card-BH7i86fH.js",
|
|
12009
|
+
"/assets/x-AhXI_F1j.js",
|
|
12010
|
+
"/assets/useOpenInteractionType-BQ1arb0B.js",
|
|
12011
|
+
"/assets/react-dom-D_m_Zgd3.js"
|
|
11112
12012
|
],
|
|
11113
12013
|
"css": [],
|
|
11114
12014
|
"clientActionModule": void 0,
|
|
@@ -11129,15 +12029,15 @@ var server_manifest_default = {
|
|
|
11129
12029
|
"hasClientMiddleware": false,
|
|
11130
12030
|
"hasDefaultExport": true,
|
|
11131
12031
|
"hasErrorBoundary": true,
|
|
11132
|
-
"module": "/assets/schedules-
|
|
12032
|
+
"module": "/assets/schedules-iYfIJxOD.js",
|
|
11133
12033
|
"imports": [
|
|
11134
|
-
"/assets/jsx-runtime-
|
|
11135
|
-
"/assets/db-link-
|
|
11136
|
-
"/assets/
|
|
11137
|
-
"/assets/badge-
|
|
11138
|
-
"/assets/
|
|
11139
|
-
"/assets/
|
|
11140
|
-
"/assets/
|
|
12034
|
+
"/assets/jsx-runtime-RQyiN6Nr.js",
|
|
12035
|
+
"/assets/db-link-BajQ1v8I.js",
|
|
12036
|
+
"/assets/button-9NpSS9Ow.js",
|
|
12037
|
+
"/assets/badge-CMnQO7Lq.js",
|
|
12038
|
+
"/assets/table-Cz7ujmH_.js",
|
|
12039
|
+
"/assets/error-card-BH7i86fH.js",
|
|
12040
|
+
"/assets/pagination-C-ohiBmY.js"
|
|
11141
12041
|
],
|
|
11142
12042
|
"css": [],
|
|
11143
12043
|
"clientActionModule": void 0,
|
|
@@ -11158,17 +12058,17 @@ var server_manifest_default = {
|
|
|
11158
12058
|
"hasClientMiddleware": false,
|
|
11159
12059
|
"hasDefaultExport": true,
|
|
11160
12060
|
"hasErrorBoundary": true,
|
|
11161
|
-
"module": "/assets/schedules._name._key-
|
|
12061
|
+
"module": "/assets/schedules._name._key-CJVu73XY.js",
|
|
11162
12062
|
"imports": [
|
|
11163
|
-
"/assets/jsx-runtime-
|
|
11164
|
-
"/assets/db-link-
|
|
11165
|
-
"/assets/
|
|
11166
|
-
"/assets/button-
|
|
11167
|
-
"/assets/
|
|
11168
|
-
"/assets/
|
|
11169
|
-
"/assets/
|
|
11170
|
-
"/assets/
|
|
11171
|
-
"/assets/
|
|
12063
|
+
"/assets/jsx-runtime-RQyiN6Nr.js",
|
|
12064
|
+
"/assets/db-link-BajQ1v8I.js",
|
|
12065
|
+
"/assets/dialog-D-oczDM2.js",
|
|
12066
|
+
"/assets/button-9NpSS9Ow.js",
|
|
12067
|
+
"/assets/error-card-BH7i86fH.js",
|
|
12068
|
+
"/assets/x-AhXI_F1j.js",
|
|
12069
|
+
"/assets/useOpenInteractionType-BQ1arb0B.js",
|
|
12070
|
+
"/assets/createLucideIcon-C-LI4enx.js",
|
|
12071
|
+
"/assets/react-dom-D_m_Zgd3.js"
|
|
11172
12072
|
],
|
|
11173
12073
|
"css": [],
|
|
11174
12074
|
"clientActionModule": void 0,
|
|
@@ -11189,12 +12089,12 @@ var server_manifest_default = {
|
|
|
11189
12089
|
"hasClientMiddleware": false,
|
|
11190
12090
|
"hasDefaultExport": true,
|
|
11191
12091
|
"hasErrorBoundary": true,
|
|
11192
|
-
"module": "/assets/schedules.new-
|
|
12092
|
+
"module": "/assets/schedules.new-Cq0Mxa7G.js",
|
|
11193
12093
|
"imports": [
|
|
11194
|
-
"/assets/jsx-runtime-
|
|
11195
|
-
"/assets/db-link-
|
|
11196
|
-
"/assets/
|
|
11197
|
-
"/assets/
|
|
12094
|
+
"/assets/jsx-runtime-RQyiN6Nr.js",
|
|
12095
|
+
"/assets/db-link-BajQ1v8I.js",
|
|
12096
|
+
"/assets/button-9NpSS9Ow.js",
|
|
12097
|
+
"/assets/error-card-BH7i86fH.js"
|
|
11198
12098
|
],
|
|
11199
12099
|
"css": [],
|
|
11200
12100
|
"clientActionModule": void 0,
|
|
@@ -11215,12 +12115,43 @@ var server_manifest_default = {
|
|
|
11215
12115
|
"hasClientMiddleware": false,
|
|
11216
12116
|
"hasDefaultExport": true,
|
|
11217
12117
|
"hasErrorBoundary": true,
|
|
11218
|
-
"module": "/assets/send-
|
|
12118
|
+
"module": "/assets/send-8X9ZisG-.js",
|
|
12119
|
+
"imports": [
|
|
12120
|
+
"/assets/jsx-runtime-RQyiN6Nr.js",
|
|
12121
|
+
"/assets/db-link-BajQ1v8I.js",
|
|
12122
|
+
"/assets/button-9NpSS9Ow.js",
|
|
12123
|
+
"/assets/error-card-BH7i86fH.js"
|
|
12124
|
+
],
|
|
12125
|
+
"css": [],
|
|
12126
|
+
"clientActionModule": void 0,
|
|
12127
|
+
"clientLoaderModule": void 0,
|
|
12128
|
+
"clientMiddlewareModule": void 0,
|
|
12129
|
+
"hydrateFallbackModule": void 0
|
|
12130
|
+
},
|
|
12131
|
+
"routes/migrations": {
|
|
12132
|
+
"id": "routes/migrations",
|
|
12133
|
+
"parentId": "root",
|
|
12134
|
+
"path": "migrations",
|
|
12135
|
+
"index": void 0,
|
|
12136
|
+
"caseSensitive": void 0,
|
|
12137
|
+
"hasAction": false,
|
|
12138
|
+
"hasLoader": true,
|
|
12139
|
+
"hasClientAction": false,
|
|
12140
|
+
"hasClientLoader": false,
|
|
12141
|
+
"hasClientMiddleware": false,
|
|
12142
|
+
"hasDefaultExport": true,
|
|
12143
|
+
"hasErrorBoundary": true,
|
|
12144
|
+
"module": "/assets/migrations-D5l0n4Jn.js",
|
|
11219
12145
|
"imports": [
|
|
11220
|
-
"/assets/jsx-runtime-
|
|
11221
|
-
"/assets/db-link-
|
|
11222
|
-
"/assets/
|
|
11223
|
-
"/assets/button-
|
|
12146
|
+
"/assets/jsx-runtime-RQyiN6Nr.js",
|
|
12147
|
+
"/assets/db-link-BajQ1v8I.js",
|
|
12148
|
+
"/assets/stat-card-dyg1wY5p.js",
|
|
12149
|
+
"/assets/button-9NpSS9Ow.js",
|
|
12150
|
+
"/assets/badge-CMnQO7Lq.js",
|
|
12151
|
+
"/assets/table-Cz7ujmH_.js",
|
|
12152
|
+
"/assets/error-card-BH7i86fH.js",
|
|
12153
|
+
"/assets/pagination-C-ohiBmY.js",
|
|
12154
|
+
"/assets/filter-select-Bn_oSiip.js"
|
|
11224
12155
|
],
|
|
11225
12156
|
"css": [],
|
|
11226
12157
|
"clientActionModule": void 0,
|
|
@@ -11241,16 +12172,16 @@ var server_manifest_default = {
|
|
|
11241
12172
|
"hasClientMiddleware": false,
|
|
11242
12173
|
"hasDefaultExport": true,
|
|
11243
12174
|
"hasErrorBoundary": true,
|
|
11244
|
-
"module": "/assets/warnings-
|
|
12175
|
+
"module": "/assets/warnings-C1R_RzIe.js",
|
|
11245
12176
|
"imports": [
|
|
11246
|
-
"/assets/jsx-runtime-
|
|
11247
|
-
"/assets/db-link-
|
|
11248
|
-
"/assets/
|
|
11249
|
-
"/assets/badge-
|
|
11250
|
-
"/assets/
|
|
11251
|
-
"/assets/
|
|
11252
|
-
"/assets/pagination-
|
|
11253
|
-
"/assets/
|
|
12177
|
+
"/assets/jsx-runtime-RQyiN6Nr.js",
|
|
12178
|
+
"/assets/db-link-BajQ1v8I.js",
|
|
12179
|
+
"/assets/button-9NpSS9Ow.js",
|
|
12180
|
+
"/assets/badge-CMnQO7Lq.js",
|
|
12181
|
+
"/assets/table-Cz7ujmH_.js",
|
|
12182
|
+
"/assets/error-card-BH7i86fH.js",
|
|
12183
|
+
"/assets/pagination-C-ohiBmY.js",
|
|
12184
|
+
"/assets/filter-select-Bn_oSiip.js"
|
|
11254
12185
|
],
|
|
11255
12186
|
"css": [],
|
|
11256
12187
|
"clientActionModule": void 0,
|
|
@@ -11259,8 +12190,8 @@ var server_manifest_default = {
|
|
|
11259
12190
|
"hydrateFallbackModule": void 0
|
|
11260
12191
|
}
|
|
11261
12192
|
},
|
|
11262
|
-
"url": "/assets/manifest-
|
|
11263
|
-
"version": "
|
|
12193
|
+
"url": "/assets/manifest-27e8e133.js",
|
|
12194
|
+
"version": "27e8e133",
|
|
11264
12195
|
"sri": void 0
|
|
11265
12196
|
};
|
|
11266
12197
|
//#endregion
|
|
@@ -11366,6 +12297,14 @@ var routes = {
|
|
|
11366
12297
|
caseSensitive: void 0,
|
|
11367
12298
|
module: send_exports
|
|
11368
12299
|
},
|
|
12300
|
+
"routes/migrations": {
|
|
12301
|
+
id: "routes/migrations",
|
|
12302
|
+
parentId: "root",
|
|
12303
|
+
path: "migrations",
|
|
12304
|
+
index: void 0,
|
|
12305
|
+
caseSensitive: void 0,
|
|
12306
|
+
module: migrations_exports
|
|
12307
|
+
},
|
|
11369
12308
|
"routes/warnings": {
|
|
11370
12309
|
id: "routes/warnings",
|
|
11371
12310
|
parentId: "root",
|