@pg-boss/dashboard 1.1.0 → 1.1.2
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/README.md +25 -173
- package/build/client/assets/MenuTrigger-CoRd-BqL.js +1 -0
- package/build/client/assets/{_index-Bcg_-XSd.js → _index-BTx7NRR8.js} +1 -1
- package/build/client/assets/{badge-Cd8v3tl3.js → badge-DBD4CzAv.js} +1 -1
- package/build/client/assets/{button-BaXUPm8v.js → button-Ba8FWhqs.js} +1 -1
- package/build/client/assets/{chevron-down-xu6Uceu-.js → chevron-down-CYa4FYmp.js} +1 -1
- package/build/client/assets/chunk-UVKPFVEO-YfSfkVr_.js +26 -0
- package/build/client/assets/{createLucideIcon-BXGwbdrh.js → createLucideIcon-Bt-yXILq.js} +1 -1
- package/build/client/assets/db-link-CU7IJqbq.js +1 -0
- package/build/client/assets/dialog-Dkx42Rkd.js +1 -0
- package/build/client/assets/{entry.client-COnaNoy-.js → entry.client-DXZUROTm.js} +4 -4
- package/build/client/assets/{error-card-DmoxS3Ao.js → error-card-D-uZRy_l.js} +1 -1
- package/build/client/assets/{filter-select-mMC79WOR.js → filter-select-Tk_CBvrn.js} +1 -1
- package/build/client/assets/{index-DhMkYPMa.js → index-DuhoQwUK.js} +1 -1
- package/build/client/assets/{jobs-DtmTCs8I.js → jobs-ouYjIGAi.js} +1 -1
- package/build/client/assets/manifest-72f6b3e9.js +1 -0
- package/build/client/assets/{pagination-NfhvsUbp.js → pagination-BItl293Q.js} +1 -1
- package/build/client/assets/{queues._index-Cw1B49mg.js → queues._index-_ID9kaow.js} +1 -1
- package/build/client/assets/{queues._name-D0cG_qDX.js → queues._name-DwdbQND-.js} +1 -1
- package/build/client/assets/{queues._name.jobs._jobId-uJ3dfM3J.js → queues._name.jobs._jobId-DrgG3VBb.js} +1 -1
- package/build/client/assets/{queues.create-BGXDhJ3m.js → queues.create-CmVW5UVm.js} +1 -1
- package/build/client/assets/root-Bpb4WtY4.css +1 -0
- package/build/client/assets/{root-NWrBrGvr.js → root-DDqOT0vL.js} +1 -1
- package/build/client/assets/{schedules-DzgBEayh.js → schedules-B6ixYsvz.js} +1 -1
- package/build/client/assets/{schedules._name._key-i42S9kw2.js → schedules._name._key-CXTVKoOc.js} +1 -1
- package/build/client/assets/{schedules.new-Dt78KptL.js → schedules.new-Dmasri9v.js} +1 -1
- package/build/client/assets/{send-0eWgiWNl.js → send-CqR34Z50.js} +1 -1
- package/build/client/assets/{table-CTo0I5HG.js → table-Au2E5mnP.js} +1 -1
- package/build/client/assets/useOpenInteractionType-mgYMZAa8.js +12 -0
- package/build/client/assets/{warnings-BhQM6lFV.js → warnings-Dj3qacgN.js} +1 -1
- package/build/server/assets/server-build.js +417 -79
- package/package.json +18 -18
- package/build/client/assets/MenuTrigger-SThQHnlb.js +0 -1
- package/build/client/assets/chunk-JZWAC4HX-DC8i-F7r.js +0 -26
- package/build/client/assets/db-link-CtPnIrIr.js +0 -1
- package/build/client/assets/dialog-Bl8T588f.js +0 -1
- package/build/client/assets/manifest-25954681.js +0 -1
- package/build/client/assets/root-DJRlbyb5.css +0 -1
- package/build/client/assets/useOpenInteractionType-C_L8nZ_l.js +0 -12
|
@@ -1428,6 +1428,7 @@ function createTableQueue(schema) {
|
|
|
1428
1428
|
warning_queued int NOT NULL default 0,
|
|
1429
1429
|
active_count int NOT NULL default 0,
|
|
1430
1430
|
total_count int NOT NULL default 0,
|
|
1431
|
+
heartbeat_seconds int,
|
|
1431
1432
|
singletons_active text[],
|
|
1432
1433
|
monitor_on timestamp with time zone,
|
|
1433
1434
|
maintain_on timestamp with time zone,
|
|
@@ -1610,11 +1611,13 @@ function createTableJob(schema) {
|
|
|
1610
1611
|
keep_until timestamp with time zone NOT NULL default now() + interval '${QUEUE_DEFAULTS.retention_seconds}',
|
|
1611
1612
|
output jsonb,
|
|
1612
1613
|
dead_letter text,
|
|
1613
|
-
policy text
|
|
1614
|
+
policy text,
|
|
1615
|
+
heartbeat_on timestamp with time zone,
|
|
1616
|
+
heartbeat_seconds int
|
|
1614
1617
|
) PARTITION BY LIST (name)
|
|
1615
1618
|
`;
|
|
1616
1619
|
}
|
|
1617
|
-
const JOB_COLUMNS_MIN = 'id, name, data, expire_seconds as "expireInSeconds", group_id as "groupId", group_tier as "groupTier"';
|
|
1620
|
+
const JOB_COLUMNS_MIN = 'id, name, data, expire_seconds as "expireInSeconds", heartbeat_seconds as "heartbeatSeconds", group_id as "groupId", group_tier as "groupTier"';
|
|
1618
1621
|
const JOB_COLUMNS_ALL = `${JOB_COLUMNS_MIN},
|
|
1619
1622
|
policy,
|
|
1620
1623
|
state,
|
|
@@ -1629,6 +1632,7 @@ const JOB_COLUMNS_ALL = `${JOB_COLUMNS_MIN},
|
|
|
1629
1632
|
singleton_key as "singletonKey",
|
|
1630
1633
|
singleton_on as "singletonOn",
|
|
1631
1634
|
deletion_seconds as "deleteAfterSeconds",
|
|
1635
|
+
heartbeat_on as "heartbeatOn",
|
|
1632
1636
|
created_on as "createdOn",
|
|
1633
1637
|
completed_on as "completedOn",
|
|
1634
1638
|
keep_until as "keepUntil",
|
|
@@ -1682,7 +1686,8 @@ function createQueueFunction(schema) {
|
|
|
1682
1686
|
warning_queued,
|
|
1683
1687
|
dead_letter,
|
|
1684
1688
|
partition,
|
|
1685
|
-
table_name
|
|
1689
|
+
table_name,
|
|
1690
|
+
heartbeat_seconds
|
|
1686
1691
|
)
|
|
1687
1692
|
VALUES (
|
|
1688
1693
|
queue_name,
|
|
@@ -1697,7 +1702,8 @@ function createQueueFunction(schema) {
|
|
|
1697
1702
|
COALESCE((options->>'warningQueueSize')::int, ${QUEUE_DEFAULTS.warning_queued}),
|
|
1698
1703
|
options->>'deadLetter',
|
|
1699
1704
|
COALESCE((options->>'partition')::bool, ${QUEUE_DEFAULTS.partition}),
|
|
1700
|
-
tablename
|
|
1705
|
+
tablename,
|
|
1706
|
+
(options->>'heartbeatSeconds')::int
|
|
1701
1707
|
)
|
|
1702
1708
|
ON CONFLICT DO NOTHING
|
|
1703
1709
|
RETURNING created_on
|
|
@@ -1854,6 +1860,9 @@ function updateQueue(schema, { deadLetter } = {}) {
|
|
|
1854
1860
|
retention_seconds = COALESCE((o.data->>'retentionSeconds')::int, retention_seconds),
|
|
1855
1861
|
deletion_seconds = COALESCE((o.data->>'deleteAfterSeconds')::int, deletion_seconds),
|
|
1856
1862
|
warning_queued = COALESCE((o.data->>'warningQueueSize')::int, warning_queued),
|
|
1863
|
+
heartbeat_seconds = CASE WHEN o.data ? 'heartbeatSeconds'
|
|
1864
|
+
THEN (o.data->>'heartbeatSeconds')::int
|
|
1865
|
+
ELSE heartbeat_seconds END,
|
|
1857
1866
|
${deadLetter === void 0 ? "" : `dead_letter = CASE WHEN '${deadLetter}' IS DISTINCT FROM dead_letter THEN '${deadLetter}' ELSE dead_letter END,`}
|
|
1858
1867
|
updated_on = now()
|
|
1859
1868
|
FROM options o
|
|
@@ -1875,6 +1884,7 @@ function getQueues$1(schema, names) {
|
|
|
1875
1884
|
q.retention_seconds as "retentionSeconds",
|
|
1876
1885
|
q.deletion_seconds as "deleteAfterSeconds",
|
|
1877
1886
|
q.partition,
|
|
1887
|
+
q.heartbeat_seconds as "heartbeatSeconds",
|
|
1878
1888
|
q.dead_letter as "deadLetter",
|
|
1879
1889
|
q.deferred_count as "deferredCount",
|
|
1880
1890
|
q.warning_queued as "warningQueueSize",
|
|
@@ -1989,10 +1999,12 @@ function insertVersion(schema, version) {
|
|
|
1989
1999
|
return `INSERT INTO ${schema}.version(version) VALUES ('${version}')`;
|
|
1990
2000
|
}
|
|
1991
2001
|
function buildFetchParams(options) {
|
|
1992
|
-
const { ignoreSingletons, ignoreGroups, groupConcurrency } = options;
|
|
2002
|
+
const { ignoreSingletons, ignoreGroups, groupConcurrency, minPriority, maxPriority } = options;
|
|
1993
2003
|
const hasIgnoreSingletons = ignoreSingletons != null && ignoreSingletons.length > 0;
|
|
1994
2004
|
const hasIgnoreGroups = ignoreGroups != null && ignoreGroups.length > 0;
|
|
1995
2005
|
const hasGroupConcurrency = groupConcurrency != null;
|
|
2006
|
+
const hasMinPriority = minPriority != null;
|
|
2007
|
+
const hasMaxPriority = maxPriority != null;
|
|
1996
2008
|
const groupConcurrencyConfig = hasGroupConcurrency ? typeof groupConcurrency === "number" ? { default: groupConcurrency } : groupConcurrency : null;
|
|
1997
2009
|
const hasTiers = groupConcurrencyConfig?.tiers && Object.keys(groupConcurrencyConfig.tiers).length > 0;
|
|
1998
2010
|
const values = [];
|
|
@@ -2001,6 +2013,8 @@ function buildFetchParams(options) {
|
|
|
2001
2013
|
let ignoreGroupsParam = "";
|
|
2002
2014
|
let defaultGroupLimitParam = "";
|
|
2003
2015
|
let tiersParam = "";
|
|
2016
|
+
let minPriorityParam = "";
|
|
2017
|
+
let maxPriorityParam = "";
|
|
2004
2018
|
if (hasIgnoreSingletons) {
|
|
2005
2019
|
paramIndex++;
|
|
2006
2020
|
ignoreSingletonsParam = `$${paramIndex}::text[]`;
|
|
@@ -2021,14 +2035,26 @@ function buildFetchParams(options) {
|
|
|
2021
2035
|
values.push(JSON.stringify(groupConcurrencyConfig.tiers));
|
|
2022
2036
|
}
|
|
2023
2037
|
}
|
|
2024
|
-
|
|
2038
|
+
if (hasMinPriority) {
|
|
2039
|
+
paramIndex++;
|
|
2040
|
+
minPriorityParam = `$${paramIndex}::int`;
|
|
2041
|
+
values.push(minPriority);
|
|
2042
|
+
}
|
|
2043
|
+
if (hasMaxPriority) {
|
|
2044
|
+
paramIndex++;
|
|
2045
|
+
maxPriorityParam = `$${paramIndex}::int`;
|
|
2046
|
+
values.push(maxPriority);
|
|
2047
|
+
}
|
|
2048
|
+
return { values, ignoreSingletonsParam, ignoreGroupsParam, defaultGroupLimitParam, tiersParam, minPriorityParam, maxPriorityParam };
|
|
2025
2049
|
}
|
|
2026
2050
|
function fetchNextJob(options) {
|
|
2027
|
-
const { schema, table, name, policy, limit, includeMetadata, priority = true, orderByCreatedOn = true, ignoreStartAfter = false, groupConcurrency } = options;
|
|
2051
|
+
const { schema, table, name, policy, limit, includeMetadata, priority = true, orderByCreatedOn = true, ignoreStartAfter = false, groupConcurrency, minPriority, maxPriority } = options;
|
|
2028
2052
|
const singletonFetch = limit > 1 && (policy === QUEUE_POLICIES.singleton || policy === QUEUE_POLICIES.stately);
|
|
2029
2053
|
const hasIgnoreSingletons = options.ignoreSingletons != null && options.ignoreSingletons.length > 0;
|
|
2030
2054
|
const hasIgnoreGroups = options.ignoreGroups != null && options.ignoreGroups.length > 0;
|
|
2031
2055
|
const hasGroupConcurrency = groupConcurrency != null;
|
|
2056
|
+
const hasMinPriority = minPriority != null;
|
|
2057
|
+
const hasMaxPriority = maxPriority != null;
|
|
2032
2058
|
const hasTiers = hasGroupConcurrency && typeof groupConcurrency === "object" && groupConcurrency.tiers && Object.keys(groupConcurrency.tiers).length > 0;
|
|
2033
2059
|
const params = buildFetchParams(options);
|
|
2034
2060
|
const whereConditions = [
|
|
@@ -2036,7 +2062,9 @@ function fetchNextJob(options) {
|
|
|
2036
2062
|
`state < '${JOB_STATES.active}'`,
|
|
2037
2063
|
!ignoreStartAfter ? "start_after < now()" : "",
|
|
2038
2064
|
hasIgnoreSingletons ? `singleton_key <> ALL(${params.ignoreSingletonsParam})` : "",
|
|
2039
|
-
hasIgnoreGroups ? `(group_id IS NULL OR group_id <> ALL(${params.ignoreGroupsParam}))` : ""
|
|
2065
|
+
hasIgnoreGroups ? `(group_id IS NULL OR group_id <> ALL(${params.ignoreGroupsParam}))` : "",
|
|
2066
|
+
hasMinPriority ? `priority >= ${params.minPriorityParam}` : "",
|
|
2067
|
+
hasMaxPriority ? `priority <= ${params.maxPriorityParam}` : ""
|
|
2040
2068
|
].filter(Boolean).join(" AND ");
|
|
2041
2069
|
const selectCols = [
|
|
2042
2070
|
"id",
|
|
@@ -2091,6 +2119,7 @@ function fetchNextJob(options) {
|
|
|
2091
2119
|
UPDATE ${schema}.${table} j SET
|
|
2092
2120
|
state = '${JOB_STATES.active}',
|
|
2093
2121
|
started_on = now(),
|
|
2122
|
+
heartbeat_on = now(),
|
|
2094
2123
|
retry_count = CASE WHEN started_on IS NOT NULL THEN retry_count + 1 ELSE retry_count END
|
|
2095
2124
|
FROM ${finalCte}
|
|
2096
2125
|
WHERE name = '${name}' AND j.id = ${finalCte}.id
|
|
@@ -2172,7 +2201,8 @@ function insertJobs(schema, { table, name, returnId = true }) {
|
|
|
2172
2201
|
retry_backoff,
|
|
2173
2202
|
retry_delay_max,
|
|
2174
2203
|
policy,
|
|
2175
|
-
dead_letter
|
|
2204
|
+
dead_letter,
|
|
2205
|
+
heartbeat_seconds
|
|
2176
2206
|
)
|
|
2177
2207
|
SELECT
|
|
2178
2208
|
COALESCE(id, gen_random_uuid()) as id,
|
|
@@ -2195,7 +2225,8 @@ function insertJobs(schema, { table, name, returnId = true }) {
|
|
|
2195
2225
|
COALESCE("retryBackoff", q.retry_backoff, false) as retry_backoff,
|
|
2196
2226
|
COALESCE("retryDelayMax", q.retry_delay_max) as retry_delay_max,
|
|
2197
2227
|
q.policy,
|
|
2198
|
-
COALESCE("deadLetter", q.dead_letter) as dead_letter
|
|
2228
|
+
COALESCE("deadLetter", q.dead_letter) as dead_letter,
|
|
2229
|
+
COALESCE("heartbeatSeconds", q.heartbeat_seconds) as heartbeat_seconds
|
|
2199
2230
|
FROM (
|
|
2200
2231
|
SELECT *,
|
|
2201
2232
|
CASE
|
|
@@ -2219,7 +2250,8 @@ function insertJobs(schema, { table, name, returnId = true }) {
|
|
|
2219
2250
|
"expireInSeconds" integer,
|
|
2220
2251
|
"deleteAfterSeconds" integer,
|
|
2221
2252
|
"retentionSeconds" integer,
|
|
2222
|
-
"deadLetter" text
|
|
2253
|
+
"deadLetter" text,
|
|
2254
|
+
"heartbeatSeconds" integer
|
|
2223
2255
|
)
|
|
2224
2256
|
) j
|
|
2225
2257
|
JOIN ${schema}.queue q ON q.name = '${name}'
|
|
@@ -2240,6 +2272,27 @@ function failJobsByTimeout(schema, table, queues) {
|
|
|
2240
2272
|
const output = `'{ "value": { "message": "job timed out" } }'::jsonb`;
|
|
2241
2273
|
return locked(schema, failJobs(schema, table, where, output), table + "failJobsByTimeout");
|
|
2242
2274
|
}
|
|
2275
|
+
function failJobsByHeartbeat(schema, table, queues) {
|
|
2276
|
+
const where = `state = '${JOB_STATES.active}'
|
|
2277
|
+
AND heartbeat_seconds IS NOT NULL
|
|
2278
|
+
AND (heartbeat_on + heartbeat_seconds * interval '1s') < now()
|
|
2279
|
+
AND name = ANY(${serializeArrayParam(queues)})`;
|
|
2280
|
+
const output = `'{ "value": { "message": "job heartbeat timeout" } }'::jsonb`;
|
|
2281
|
+
return locked(schema, failJobs(schema, table, where, output), table + "failJobsByHeartbeat");
|
|
2282
|
+
}
|
|
2283
|
+
function touchJobs(schema, table) {
|
|
2284
|
+
return `
|
|
2285
|
+
WITH results AS (
|
|
2286
|
+
UPDATE ${schema}.${table}
|
|
2287
|
+
SET heartbeat_on = now()
|
|
2288
|
+
WHERE name = $1
|
|
2289
|
+
AND id IN (SELECT UNNEST($2::uuid[]))
|
|
2290
|
+
AND state = '${JOB_STATES.active}'
|
|
2291
|
+
RETURNING 1
|
|
2292
|
+
)
|
|
2293
|
+
SELECT COUNT(*) FROM results
|
|
2294
|
+
`;
|
|
2295
|
+
}
|
|
2243
2296
|
function failJobs(schema, table, where, output) {
|
|
2244
2297
|
return `
|
|
2245
2298
|
WITH deleted_jobs AS (
|
|
@@ -2272,7 +2325,9 @@ function failJobs(schema, table, where, output) {
|
|
|
2272
2325
|
keep_until,
|
|
2273
2326
|
policy,
|
|
2274
2327
|
output,
|
|
2275
|
-
dead_letter
|
|
2328
|
+
dead_letter,
|
|
2329
|
+
heartbeat_on,
|
|
2330
|
+
heartbeat_seconds
|
|
2276
2331
|
)
|
|
2277
2332
|
SELECT
|
|
2278
2333
|
id,
|
|
@@ -2310,7 +2365,9 @@ function failJobs(schema, table, where, output) {
|
|
|
2310
2365
|
keep_until,
|
|
2311
2366
|
policy,
|
|
2312
2367
|
${output},
|
|
2313
|
-
dead_letter
|
|
2368
|
+
dead_letter,
|
|
2369
|
+
NULL as heartbeat_on,
|
|
2370
|
+
heartbeat_seconds
|
|
2314
2371
|
FROM deleted_jobs
|
|
2315
2372
|
ON CONFLICT DO NOTHING
|
|
2316
2373
|
RETURNING *
|
|
@@ -2340,7 +2397,9 @@ function failJobs(schema, table, where, output) {
|
|
|
2340
2397
|
keep_until,
|
|
2341
2398
|
policy,
|
|
2342
2399
|
output,
|
|
2343
|
-
dead_letter
|
|
2400
|
+
dead_letter,
|
|
2401
|
+
heartbeat_on,
|
|
2402
|
+
heartbeat_seconds
|
|
2344
2403
|
)
|
|
2345
2404
|
SELECT
|
|
2346
2405
|
id,
|
|
@@ -2366,7 +2425,9 @@ function failJobs(schema, table, where, output) {
|
|
|
2366
2425
|
keep_until,
|
|
2367
2426
|
policy,
|
|
2368
2427
|
${output},
|
|
2369
|
-
dead_letter
|
|
2428
|
+
dead_letter,
|
|
2429
|
+
NULL as heartbeat_on,
|
|
2430
|
+
heartbeat_seconds
|
|
2370
2431
|
FROM deleted_jobs
|
|
2371
2432
|
WHERE id NOT IN (SELECT id from retried_jobs)
|
|
2372
2433
|
RETURNING *
|
|
@@ -2579,7 +2640,7 @@ const POLICY = {
|
|
|
2579
2640
|
MAX_RETENTION_DAYS: 365
|
|
2580
2641
|
};
|
|
2581
2642
|
function assertObjectName(value, name = "Name") {
|
|
2582
|
-
assert(/^[\w
|
|
2643
|
+
assert(/^[\w.\-/]+$/.test(value), `${name} can only contain alphanumeric characters, underscores, hyphens, periods, or forward slashes`);
|
|
2583
2644
|
}
|
|
2584
2645
|
function validateQueueArgs(config = {}) {
|
|
2585
2646
|
assert(!("deadLetter" in config) || config.deadLetter === null || typeof config.deadLetter === "string", "deadLetter must be a string");
|
|
@@ -2590,6 +2651,7 @@ function validateQueueArgs(config = {}) {
|
|
|
2590
2651
|
validateExpirationConfig(config);
|
|
2591
2652
|
validateRetentionConfig(config);
|
|
2592
2653
|
validateDeletionConfig(config);
|
|
2654
|
+
validateHeartbeatConfig(config);
|
|
2593
2655
|
}
|
|
2594
2656
|
function checkSendArgs(args) {
|
|
2595
2657
|
let name, data, options;
|
|
@@ -2618,6 +2680,7 @@ function checkSendArgs(args) {
|
|
|
2618
2680
|
validateRetentionConfig(options);
|
|
2619
2681
|
validateDeletionConfig(options);
|
|
2620
2682
|
validateGroupConfig(options);
|
|
2683
|
+
validateHeartbeatConfig(options);
|
|
2621
2684
|
return { name, data, options };
|
|
2622
2685
|
}
|
|
2623
2686
|
function validateGroupConfig(config) {
|
|
@@ -2643,6 +2706,17 @@ function validateGroupConcurrencyValue(value, optionName) {
|
|
|
2643
2706
|
}
|
|
2644
2707
|
}
|
|
2645
2708
|
}
|
|
2709
|
+
function validatePriorityRangeConfig(config) {
|
|
2710
|
+
if (config.minPriority !== void 0) {
|
|
2711
|
+
assert(Number.isInteger(config.minPriority), "minPriority must be an integer");
|
|
2712
|
+
}
|
|
2713
|
+
if (config.maxPriority !== void 0) {
|
|
2714
|
+
assert(Number.isInteger(config.maxPriority), "maxPriority must be an integer");
|
|
2715
|
+
}
|
|
2716
|
+
if (config.minPriority !== void 0 && config.maxPriority !== void 0) {
|
|
2717
|
+
assert(config.minPriority <= config.maxPriority, "minPriority must be <= maxPriority");
|
|
2718
|
+
}
|
|
2719
|
+
}
|
|
2646
2720
|
function validateGroupConcurrencyConfig(config) {
|
|
2647
2721
|
const hasGlobal = config.groupConcurrency != null;
|
|
2648
2722
|
const hasLocal = config.localGroupConcurrency != null;
|
|
@@ -2696,7 +2770,9 @@ function checkWorkArgs(name, args) {
|
|
|
2696
2770
|
assert(!("includeMetadata" in options) || typeof options.includeMetadata === "boolean", "includeMetadata must be a boolean");
|
|
2697
2771
|
assert(!("priority" in options) || typeof options.priority === "boolean", "priority must be a boolean");
|
|
2698
2772
|
assert(!("localConcurrency" in options) || Number.isInteger(options.localConcurrency) && options.localConcurrency >= 1, "localConcurrency must be an integer >= 1");
|
|
2773
|
+
validatePriorityRangeConfig(options);
|
|
2699
2774
|
validateGroupConcurrencyConfig(options);
|
|
2775
|
+
validateHeartbeatRefreshConfig(options);
|
|
2700
2776
|
return { options, callback };
|
|
2701
2777
|
}
|
|
2702
2778
|
function checkFetchArgs(name, options) {
|
|
@@ -2705,6 +2781,7 @@ function checkFetchArgs(name, options) {
|
|
|
2705
2781
|
assert(!("includeMetadata" in options) || typeof options.includeMetadata === "boolean", "includeMetadata must be a boolean");
|
|
2706
2782
|
assert(!("priority" in options) || typeof options.priority === "boolean", "priority must be a boolean");
|
|
2707
2783
|
assert(!("ignoreStartAfter" in options) || typeof options.ignoreStartAfter === "boolean", "ignoreStartAfter must be a boolean");
|
|
2784
|
+
validatePriorityRangeConfig(options);
|
|
2708
2785
|
}
|
|
2709
2786
|
function getConfig(value) {
|
|
2710
2787
|
assert(
|
|
@@ -2783,6 +2860,19 @@ function validateRetryConfig(config) {
|
|
|
2783
2860
|
assert(!("retryDelayMax" in config) || config.retryDelayMax === null || config.retryBackoff === true, "retryDelayMax can only be set if retryBackoff is true");
|
|
2784
2861
|
assert(!("retryDelayMax" in config) || config.retryDelayMax === null || Number.isInteger(config.retryDelayMax) && config.retryDelayMax >= 0, "retryDelayMax must be an integer >= 0");
|
|
2785
2862
|
}
|
|
2863
|
+
function validateHeartbeatConfig(config) {
|
|
2864
|
+
assert(
|
|
2865
|
+
!("heartbeatSeconds" in config) || config.heartbeatSeconds === null || Number.isInteger(config.heartbeatSeconds) && config.heartbeatSeconds >= 10,
|
|
2866
|
+
"heartbeatSeconds must be an integer >= 10"
|
|
2867
|
+
);
|
|
2868
|
+
}
|
|
2869
|
+
function validateHeartbeatRefreshConfig(config) {
|
|
2870
|
+
if (!("heartbeatRefreshSeconds" in config) || config.heartbeatRefreshSeconds == null) return;
|
|
2871
|
+
assert(
|
|
2872
|
+
typeof config.heartbeatRefreshSeconds === "number" && config.heartbeatRefreshSeconds > 0,
|
|
2873
|
+
"heartbeatRefreshSeconds must be a number > 0"
|
|
2874
|
+
);
|
|
2875
|
+
}
|
|
2786
2876
|
function applyPollingInterval(config) {
|
|
2787
2877
|
assert(
|
|
2788
2878
|
!("pollingIntervalSeconds" in config) || config.pollingIntervalSeconds >= POLICY.MIN_POLLING_INTERVAL_MS / 1e3,
|
|
@@ -3478,10 +3568,190 @@ function getAll(schema) {
|
|
|
3478
3568
|
`DROP INDEX ${schema}.warning_i1`,
|
|
3479
3569
|
`DROP TABLE ${schema}.warning`
|
|
3480
3570
|
]
|
|
3571
|
+
},
|
|
3572
|
+
{
|
|
3573
|
+
release: "12.12.0",
|
|
3574
|
+
version: 30,
|
|
3575
|
+
previous: 29,
|
|
3576
|
+
install: [
|
|
3577
|
+
`ALTER TABLE ${schema}.job ADD COLUMN heartbeat_on timestamp with time zone`,
|
|
3578
|
+
`ALTER TABLE ${schema}.job ADD COLUMN heartbeat_seconds int`,
|
|
3579
|
+
`ALTER TABLE ${schema}.queue ADD COLUMN heartbeat_seconds int`,
|
|
3580
|
+
`
|
|
3581
|
+
CREATE OR REPLACE FUNCTION ${schema}.create_queue(queue_name text, options jsonb)
|
|
3582
|
+
RETURNS VOID AS
|
|
3583
|
+
$$
|
|
3584
|
+
DECLARE
|
|
3585
|
+
tablename varchar := CASE WHEN options->>'partition' = 'true'
|
|
3586
|
+
THEN 'j' || encode(sha224(queue_name::bytea), 'hex')
|
|
3587
|
+
ELSE 'job_common'
|
|
3588
|
+
END;
|
|
3589
|
+
queue_created_on timestamptz;
|
|
3590
|
+
BEGIN
|
|
3591
|
+
|
|
3592
|
+
WITH q as (
|
|
3593
|
+
INSERT INTO ${schema}.queue (
|
|
3594
|
+
name,
|
|
3595
|
+
policy,
|
|
3596
|
+
retry_limit,
|
|
3597
|
+
retry_delay,
|
|
3598
|
+
retry_backoff,
|
|
3599
|
+
retry_delay_max,
|
|
3600
|
+
expire_seconds,
|
|
3601
|
+
retention_seconds,
|
|
3602
|
+
deletion_seconds,
|
|
3603
|
+
warning_queued,
|
|
3604
|
+
dead_letter,
|
|
3605
|
+
partition,
|
|
3606
|
+
table_name,
|
|
3607
|
+
heartbeat_seconds
|
|
3608
|
+
)
|
|
3609
|
+
VALUES (
|
|
3610
|
+
queue_name,
|
|
3611
|
+
options->>'policy',
|
|
3612
|
+
COALESCE((options->>'retryLimit')::int, 2),
|
|
3613
|
+
COALESCE((options->>'retryDelay')::int, 0),
|
|
3614
|
+
COALESCE((options->>'retryBackoff')::bool, false),
|
|
3615
|
+
(options->>'retryDelayMax')::int,
|
|
3616
|
+
COALESCE((options->>'expireInSeconds')::int, 900),
|
|
3617
|
+
COALESCE((options->>'retentionSeconds')::int, 1209600),
|
|
3618
|
+
COALESCE((options->>'deleteAfterSeconds')::int, 604800),
|
|
3619
|
+
COALESCE((options->>'warningQueueSize')::int, 0),
|
|
3620
|
+
options->>'deadLetter',
|
|
3621
|
+
COALESCE((options->>'partition')::bool, false),
|
|
3622
|
+
tablename,
|
|
3623
|
+
(options->>'heartbeatSeconds')::int
|
|
3624
|
+
)
|
|
3625
|
+
ON CONFLICT DO NOTHING
|
|
3626
|
+
RETURNING created_on
|
|
3627
|
+
)
|
|
3628
|
+
SELECT created_on into queue_created_on from q;
|
|
3629
|
+
|
|
3630
|
+
IF queue_created_on IS NULL OR options->>'partition' IS DISTINCT FROM 'true' THEN
|
|
3631
|
+
RETURN;
|
|
3632
|
+
END IF;
|
|
3633
|
+
|
|
3634
|
+
EXECUTE format('CREATE TABLE ${schema}.%I (LIKE ${schema}.job INCLUDING DEFAULTS)', tablename);
|
|
3635
|
+
|
|
3636
|
+
EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD PRIMARY KEY (name, id)$cmd$, tablename);
|
|
3637
|
+
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);
|
|
3638
|
+
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);
|
|
3639
|
+
|
|
3640
|
+
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);
|
|
3641
|
+
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);
|
|
3642
|
+
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);
|
|
3643
|
+
|
|
3644
|
+
IF options->>'policy' = 'short' THEN
|
|
3645
|
+
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);
|
|
3646
|
+
ELSIF options->>'policy' = 'singleton' THEN
|
|
3647
|
+
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);
|
|
3648
|
+
ELSIF options->>'policy' = 'stately' THEN
|
|
3649
|
+
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);
|
|
3650
|
+
ELSIF options->>'policy' = 'exclusive' THEN
|
|
3651
|
+
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);
|
|
3652
|
+
ELSIF options->>'policy' = 'key_strict_fifo' THEN
|
|
3653
|
+
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);
|
|
3654
|
+
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);
|
|
3655
|
+
END IF;
|
|
3656
|
+
|
|
3657
|
+
EXECUTE format('ALTER TABLE ${schema}.%I ADD CONSTRAINT cjc CHECK (name=%L)', tablename, queue_name);
|
|
3658
|
+
EXECUTE format('ALTER TABLE ${schema}.job ATTACH PARTITION ${schema}.%I FOR VALUES IN (%L)', tablename, queue_name);
|
|
3659
|
+
END;
|
|
3660
|
+
$$
|
|
3661
|
+
LANGUAGE plpgsql;
|
|
3662
|
+
`
|
|
3663
|
+
],
|
|
3664
|
+
uninstall: [
|
|
3665
|
+
// Restore previous version of create_queue function (without heartbeat_seconds)
|
|
3666
|
+
`
|
|
3667
|
+
CREATE OR REPLACE FUNCTION ${schema}.create_queue(queue_name text, options jsonb)
|
|
3668
|
+
RETURNS VOID AS
|
|
3669
|
+
$$
|
|
3670
|
+
DECLARE
|
|
3671
|
+
tablename varchar := CASE WHEN options->>'partition' = 'true'
|
|
3672
|
+
THEN 'j' || encode(sha224(queue_name::bytea), 'hex')
|
|
3673
|
+
ELSE 'job_common'
|
|
3674
|
+
END;
|
|
3675
|
+
queue_created_on timestamptz;
|
|
3676
|
+
BEGIN
|
|
3677
|
+
|
|
3678
|
+
WITH q as (
|
|
3679
|
+
INSERT INTO ${schema}.queue (
|
|
3680
|
+
name,
|
|
3681
|
+
policy,
|
|
3682
|
+
retry_limit,
|
|
3683
|
+
retry_delay,
|
|
3684
|
+
retry_backoff,
|
|
3685
|
+
retry_delay_max,
|
|
3686
|
+
expire_seconds,
|
|
3687
|
+
retention_seconds,
|
|
3688
|
+
deletion_seconds,
|
|
3689
|
+
warning_queued,
|
|
3690
|
+
dead_letter,
|
|
3691
|
+
partition,
|
|
3692
|
+
table_name
|
|
3693
|
+
)
|
|
3694
|
+
VALUES (
|
|
3695
|
+
queue_name,
|
|
3696
|
+
options->>'policy',
|
|
3697
|
+
COALESCE((options->>'retryLimit')::int, 2),
|
|
3698
|
+
COALESCE((options->>'retryDelay')::int, 0),
|
|
3699
|
+
COALESCE((options->>'retryBackoff')::bool, false),
|
|
3700
|
+
(options->>'retryDelayMax')::int,
|
|
3701
|
+
COALESCE((options->>'expireInSeconds')::int, 900),
|
|
3702
|
+
COALESCE((options->>'retentionSeconds')::int, 1209600),
|
|
3703
|
+
COALESCE((options->>'deleteAfterSeconds')::int, 604800),
|
|
3704
|
+
COALESCE((options->>'warningQueueSize')::int, 0),
|
|
3705
|
+
options->>'deadLetter',
|
|
3706
|
+
COALESCE((options->>'partition')::bool, false),
|
|
3707
|
+
tablename
|
|
3708
|
+
)
|
|
3709
|
+
ON CONFLICT DO NOTHING
|
|
3710
|
+
RETURNING created_on
|
|
3711
|
+
)
|
|
3712
|
+
SELECT created_on into queue_created_on from q;
|
|
3713
|
+
|
|
3714
|
+
IF queue_created_on IS NULL OR options->>'partition' IS DISTINCT FROM 'true' THEN
|
|
3715
|
+
RETURN;
|
|
3716
|
+
END IF;
|
|
3717
|
+
|
|
3718
|
+
EXECUTE format('CREATE TABLE ${schema}.%I (LIKE ${schema}.job INCLUDING DEFAULTS)', tablename);
|
|
3719
|
+
|
|
3720
|
+
EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD PRIMARY KEY (name, id)$cmd$, tablename);
|
|
3721
|
+
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);
|
|
3722
|
+
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);
|
|
3723
|
+
|
|
3724
|
+
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);
|
|
3725
|
+
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);
|
|
3726
|
+
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);
|
|
3727
|
+
|
|
3728
|
+
IF options->>'policy' = 'short' THEN
|
|
3729
|
+
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);
|
|
3730
|
+
ELSIF options->>'policy' = 'singleton' THEN
|
|
3731
|
+
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);
|
|
3732
|
+
ELSIF options->>'policy' = 'stately' THEN
|
|
3733
|
+
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);
|
|
3734
|
+
ELSIF options->>'policy' = 'exclusive' THEN
|
|
3735
|
+
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);
|
|
3736
|
+
ELSIF options->>'policy' = 'key_strict_fifo' THEN
|
|
3737
|
+
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);
|
|
3738
|
+
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);
|
|
3739
|
+
END IF;
|
|
3740
|
+
|
|
3741
|
+
EXECUTE format('ALTER TABLE ${schema}.%I ADD CONSTRAINT cjc CHECK (name=%L)', tablename, queue_name);
|
|
3742
|
+
EXECUTE format('ALTER TABLE ${schema}.job ATTACH PARTITION ${schema}.%I FOR VALUES IN (%L)', tablename, queue_name);
|
|
3743
|
+
END;
|
|
3744
|
+
$$
|
|
3745
|
+
LANGUAGE plpgsql;
|
|
3746
|
+
`,
|
|
3747
|
+
`ALTER TABLE ${schema}.queue DROP COLUMN heartbeat_seconds`,
|
|
3748
|
+
`ALTER TABLE ${schema}.job DROP COLUMN heartbeat_seconds`,
|
|
3749
|
+
`ALTER TABLE ${schema}.job DROP COLUMN heartbeat_on`
|
|
3750
|
+
]
|
|
3481
3751
|
}
|
|
3482
3752
|
];
|
|
3483
3753
|
}
|
|
3484
|
-
const pgboss = { "schema":
|
|
3754
|
+
const pgboss = { "schema": 30 };
|
|
3485
3755
|
const packageJson = {
|
|
3486
3756
|
pgboss
|
|
3487
3757
|
};
|
|
@@ -3558,6 +3828,41 @@ class Contractor {
|
|
|
3558
3828
|
await this.db.executeSql(commands);
|
|
3559
3829
|
}
|
|
3560
3830
|
}
|
|
3831
|
+
function unwrapSQLResult(result) {
|
|
3832
|
+
if (Array.isArray(result)) {
|
|
3833
|
+
return { rows: result.flatMap((i) => i.rows) };
|
|
3834
|
+
}
|
|
3835
|
+
return result;
|
|
3836
|
+
}
|
|
3837
|
+
function delay(ms, error, abortController) {
|
|
3838
|
+
const ac = abortController || new AbortController();
|
|
3839
|
+
const promise = new Promise((resolve, reject) => {
|
|
3840
|
+
setTimeout$1(ms, null, { signal: ac.signal }).then(() => {
|
|
3841
|
+
if (error) {
|
|
3842
|
+
reject(new Error(error));
|
|
3843
|
+
} else {
|
|
3844
|
+
resolve();
|
|
3845
|
+
}
|
|
3846
|
+
}).catch(resolve);
|
|
3847
|
+
});
|
|
3848
|
+
promise.abort = () => {
|
|
3849
|
+
if (!ac.signal.aborted) {
|
|
3850
|
+
ac.abort();
|
|
3851
|
+
}
|
|
3852
|
+
};
|
|
3853
|
+
return promise;
|
|
3854
|
+
}
|
|
3855
|
+
async function resolveWithinSeconds(promise, seconds, message, abortController) {
|
|
3856
|
+
const timeout = Math.max(1, seconds) * 1e3;
|
|
3857
|
+
const reject = delay(timeout, message, abortController);
|
|
3858
|
+
let result;
|
|
3859
|
+
try {
|
|
3860
|
+
result = await Promise.race([promise, reject]);
|
|
3861
|
+
} finally {
|
|
3862
|
+
reject.abort();
|
|
3863
|
+
}
|
|
3864
|
+
return result;
|
|
3865
|
+
}
|
|
3561
3866
|
async function emitAndPersistWarning(ctx, type, message, data) {
|
|
3562
3867
|
ctx.emitter.emit(ctx.warningEvent, { message, data });
|
|
3563
3868
|
if (ctx.persistWarnings) {
|
|
@@ -3593,6 +3898,7 @@ class Timekeeper extends EventEmitter {
|
|
|
3593
3898
|
cronMonitorInterval;
|
|
3594
3899
|
skewMonitorInterval;
|
|
3595
3900
|
timekeeping;
|
|
3901
|
+
_checkingSkew = false;
|
|
3596
3902
|
clockSkew = 0;
|
|
3597
3903
|
events = EVENTS;
|
|
3598
3904
|
constructor(db, manager, config) {
|
|
@@ -3601,6 +3907,9 @@ class Timekeeper extends EventEmitter {
|
|
|
3601
3907
|
this.config = config;
|
|
3602
3908
|
this.manager = manager;
|
|
3603
3909
|
}
|
|
3910
|
+
get checkingSkew() {
|
|
3911
|
+
return this._checkingSkew;
|
|
3912
|
+
}
|
|
3604
3913
|
get warningContext() {
|
|
3605
3914
|
return {
|
|
3606
3915
|
emitter: this,
|
|
@@ -3638,13 +3947,20 @@ class Timekeeper extends EventEmitter {
|
|
|
3638
3947
|
clearInterval(this.cronMonitorInterval);
|
|
3639
3948
|
this.cronMonitorInterval = null;
|
|
3640
3949
|
}
|
|
3950
|
+
while (this.timekeeping || this._checkingSkew) {
|
|
3951
|
+
await delay(10);
|
|
3952
|
+
}
|
|
3641
3953
|
}
|
|
3642
3954
|
async cacheClockSkew() {
|
|
3643
3955
|
let skew = 0;
|
|
3956
|
+
this._checkingSkew = true;
|
|
3644
3957
|
try {
|
|
3645
3958
|
if (this.config.__test__force_clock_monitoring_error) {
|
|
3646
3959
|
throw new Error(this.config.__test__force_clock_monitoring_error);
|
|
3647
3960
|
}
|
|
3961
|
+
if (this.config.__test__delay_clock_skew_ms) {
|
|
3962
|
+
await delay(this.config.__test__delay_clock_skew_ms);
|
|
3963
|
+
}
|
|
3648
3964
|
const { rows } = await this.db.executeSql(getTime());
|
|
3649
3965
|
const local = Date.now();
|
|
3650
3966
|
const dbTime = parseFloat(rows[0].time);
|
|
@@ -3662,6 +3978,7 @@ class Timekeeper extends EventEmitter {
|
|
|
3662
3978
|
this.emit(this.events.error, err);
|
|
3663
3979
|
} finally {
|
|
3664
3980
|
this.clockSkew = skew;
|
|
3981
|
+
this._checkingSkew = false;
|
|
3665
3982
|
}
|
|
3666
3983
|
}
|
|
3667
3984
|
async onCron() {
|
|
@@ -3731,41 +4048,6 @@ class Timekeeper extends EventEmitter {
|
|
|
3731
4048
|
await this.db.executeSql(sql, [name, key]);
|
|
3732
4049
|
}
|
|
3733
4050
|
}
|
|
3734
|
-
function unwrapSQLResult(result) {
|
|
3735
|
-
if (Array.isArray(result)) {
|
|
3736
|
-
return { rows: result.flatMap((i) => i.rows) };
|
|
3737
|
-
}
|
|
3738
|
-
return result;
|
|
3739
|
-
}
|
|
3740
|
-
function delay(ms, error, abortController) {
|
|
3741
|
-
const ac = abortController || new AbortController();
|
|
3742
|
-
const promise = new Promise((resolve, reject) => {
|
|
3743
|
-
setTimeout$1(ms, null, { signal: ac.signal }).then(() => {
|
|
3744
|
-
if (error) {
|
|
3745
|
-
reject(new Error(error));
|
|
3746
|
-
} else {
|
|
3747
|
-
resolve();
|
|
3748
|
-
}
|
|
3749
|
-
}).catch(resolve);
|
|
3750
|
-
});
|
|
3751
|
-
promise.abort = () => {
|
|
3752
|
-
if (!ac.signal.aborted) {
|
|
3753
|
-
ac.abort();
|
|
3754
|
-
}
|
|
3755
|
-
};
|
|
3756
|
-
return promise;
|
|
3757
|
-
}
|
|
3758
|
-
async function resolveWithinSeconds(promise, seconds, message, abortController) {
|
|
3759
|
-
const timeout = Math.max(1, seconds) * 1e3;
|
|
3760
|
-
const reject = delay(timeout, message, abortController);
|
|
3761
|
-
let result;
|
|
3762
|
-
try {
|
|
3763
|
-
result = await Promise.race([promise, reject]);
|
|
3764
|
-
} finally {
|
|
3765
|
-
reject.abort();
|
|
3766
|
-
}
|
|
3767
|
-
return result;
|
|
3768
|
-
}
|
|
3769
4051
|
const WORKER_STATES = {
|
|
3770
4052
|
created: "created",
|
|
3771
4053
|
active: "active",
|
|
@@ -4098,9 +4380,10 @@ class Manager extends EventEmitter {
|
|
|
4098
4380
|
}
|
|
4099
4381
|
}
|
|
4100
4382
|
}
|
|
4101
|
-
async #processJobs(name, jobs2, callback, worker) {
|
|
4383
|
+
async #processJobs(name, jobs2, callback, worker, heartbeatRefreshSeconds) {
|
|
4102
4384
|
const jobIds = jobs2.map((job) => job.id);
|
|
4103
4385
|
const maxExpiration = jobs2.reduce((acc, i) => Math.max(acc, i.expireInSeconds), 0);
|
|
4386
|
+
const heartbeatSeconds = jobs2.reduce((acc, j) => Math.max(acc, j.heartbeatSeconds || 0), 0);
|
|
4104
4387
|
const ac = new AbortController();
|
|
4105
4388
|
jobs2.forEach((job) => {
|
|
4106
4389
|
job.signal = ac.signal;
|
|
@@ -4108,6 +4391,18 @@ class Manager extends EventEmitter {
|
|
|
4108
4391
|
if (worker) {
|
|
4109
4392
|
worker.abortController = ac;
|
|
4110
4393
|
}
|
|
4394
|
+
let heartbeatTimer = null;
|
|
4395
|
+
if (heartbeatSeconds > 0) {
|
|
4396
|
+
const refreshSeconds = heartbeatRefreshSeconds ?? heartbeatSeconds / 2;
|
|
4397
|
+
const intervalMs = refreshSeconds * 1e3;
|
|
4398
|
+
heartbeatTimer = setInterval(async () => {
|
|
4399
|
+
try {
|
|
4400
|
+
await this.touch(name, jobIds);
|
|
4401
|
+
} catch (err) {
|
|
4402
|
+
this.emit(events$3.error, err);
|
|
4403
|
+
}
|
|
4404
|
+
}, intervalMs);
|
|
4405
|
+
}
|
|
4111
4406
|
try {
|
|
4112
4407
|
const result = await resolveWithinSeconds(callback(jobs2), maxExpiration, `handler execution exceeded ${maxExpiration}s`, ac);
|
|
4113
4408
|
await this.complete(name, jobIds, jobIds.length === 1 ? result : void 0);
|
|
@@ -4116,6 +4411,7 @@ class Manager extends EventEmitter {
|
|
|
4116
4411
|
await this.fail(name, jobIds, err);
|
|
4117
4412
|
this.#trackJobsFailed(name, jobs2, err);
|
|
4118
4413
|
} finally {
|
|
4414
|
+
if (heartbeatTimer) clearInterval(heartbeatTimer);
|
|
4119
4415
|
if (worker) {
|
|
4120
4416
|
worker.abortController = null;
|
|
4121
4417
|
}
|
|
@@ -4182,7 +4478,10 @@ class Manager extends EventEmitter {
|
|
|
4182
4478
|
localConcurrency = 1,
|
|
4183
4479
|
localGroupConcurrency,
|
|
4184
4480
|
groupConcurrency,
|
|
4185
|
-
orderByCreatedOn = true
|
|
4481
|
+
orderByCreatedOn = true,
|
|
4482
|
+
heartbeatRefreshSeconds,
|
|
4483
|
+
minPriority,
|
|
4484
|
+
maxPriority
|
|
4186
4485
|
} = options;
|
|
4187
4486
|
if (localGroupConcurrency != null) {
|
|
4188
4487
|
this.#storeLocalGroupConfig(name, localGroupConcurrency);
|
|
@@ -4191,7 +4490,7 @@ class Manager extends EventEmitter {
|
|
|
4191
4490
|
const createWorker = (workerId) => {
|
|
4192
4491
|
const fetch = () => {
|
|
4193
4492
|
const ignoreGroups = localGroupConcurrency != null ? this.#getGroupsAtLocalCapacity(name) : void 0;
|
|
4194
|
-
return this.fetch(name, { batchSize, includeMetadata, priority, orderByCreatedOn, groupConcurrency, ignoreGroups });
|
|
4493
|
+
return this.fetch(name, { batchSize, includeMetadata, priority, orderByCreatedOn, groupConcurrency, ignoreGroups, minPriority, maxPriority });
|
|
4195
4494
|
};
|
|
4196
4495
|
const onFetch = async (jobs2) => {
|
|
4197
4496
|
if (!jobs2.length) return;
|
|
@@ -4200,7 +4499,7 @@ class Manager extends EventEmitter {
|
|
|
4200
4499
|
this.#trackJobsActive(name, jobs2);
|
|
4201
4500
|
const worker = this.workers.get(workerId);
|
|
4202
4501
|
if (localGroupConcurrency == null) {
|
|
4203
|
-
await this.#processJobs(name, jobs2, callback, worker);
|
|
4502
|
+
await this.#processJobs(name, jobs2, callback, worker, heartbeatRefreshSeconds);
|
|
4204
4503
|
} else {
|
|
4205
4504
|
const { allowed, excess, groupedJobs } = this.#trackLocalGroupStart(name, jobs2);
|
|
4206
4505
|
if (excess.length > 0) {
|
|
@@ -4209,7 +4508,7 @@ class Manager extends EventEmitter {
|
|
|
4209
4508
|
}
|
|
4210
4509
|
if (allowed.length > 0) {
|
|
4211
4510
|
try {
|
|
4212
|
-
await this.#processJobs(name, allowed, callback, worker);
|
|
4511
|
+
await this.#processJobs(name, allowed, callback, worker, heartbeatRefreshSeconds);
|
|
4213
4512
|
} finally {
|
|
4214
4513
|
this.#trackLocalGroupEnd(name, groupedJobs);
|
|
4215
4514
|
}
|
|
@@ -4346,6 +4645,7 @@ class Manager extends EventEmitter {
|
|
|
4346
4645
|
retryDelay,
|
|
4347
4646
|
retryBackoff,
|
|
4348
4647
|
retryDelayMax,
|
|
4648
|
+
heartbeatSeconds,
|
|
4349
4649
|
group,
|
|
4350
4650
|
deadLetter = null
|
|
4351
4651
|
} = options;
|
|
@@ -4368,6 +4668,7 @@ class Manager extends EventEmitter {
|
|
|
4368
4668
|
retryDelay,
|
|
4369
4669
|
retryBackoff,
|
|
4370
4670
|
retryDelayMax,
|
|
4671
|
+
heartbeatSeconds,
|
|
4371
4672
|
deadLetter
|
|
4372
4673
|
};
|
|
4373
4674
|
const db = wrapper || this.db;
|
|
@@ -4543,6 +4844,15 @@ class Manager extends EventEmitter {
|
|
|
4543
4844
|
const result = await db.executeSql(sql, [name, ids]);
|
|
4544
4845
|
return this.mapCommandResponse(ids, result);
|
|
4545
4846
|
}
|
|
4847
|
+
async touch(name, id, options = {}) {
|
|
4848
|
+
assertQueueName(name);
|
|
4849
|
+
const db = this.assertDb(options);
|
|
4850
|
+
const ids = this.mapCompletionIdArg(id, "touch");
|
|
4851
|
+
const { table } = await this.getQueueCache(name);
|
|
4852
|
+
const sql = touchJobs(this.config.schema, table);
|
|
4853
|
+
const result = await db.executeSql(sql, [name, ids]);
|
|
4854
|
+
return this.mapCommandResponse(ids, result);
|
|
4855
|
+
}
|
|
4546
4856
|
async createQueue(name, options = {}) {
|
|
4547
4857
|
name = name || options.name;
|
|
4548
4858
|
assertQueueName(name);
|
|
@@ -4729,6 +5039,9 @@ class Boss extends EventEmitter {
|
|
|
4729
5039
|
WARNINGS.LARGE_QUEUE.size = config.warningQueueSize;
|
|
4730
5040
|
}
|
|
4731
5041
|
}
|
|
5042
|
+
get maintaining() {
|
|
5043
|
+
return !!this.#maintaining;
|
|
5044
|
+
}
|
|
4732
5045
|
async start() {
|
|
4733
5046
|
if (this.#stopped) {
|
|
4734
5047
|
this.#stopping = false;
|
|
@@ -4744,6 +5057,9 @@ class Boss extends EventEmitter {
|
|
|
4744
5057
|
this.#stopping = true;
|
|
4745
5058
|
if (this.#superviseInterval) clearInterval(this.#superviseInterval);
|
|
4746
5059
|
this.#stopped = true;
|
|
5060
|
+
while (this.#maintaining) {
|
|
5061
|
+
await delay(10);
|
|
5062
|
+
}
|
|
4747
5063
|
}
|
|
4748
5064
|
}
|
|
4749
5065
|
get #warningContext() {
|
|
@@ -4756,21 +5072,10 @@ class Boss extends EventEmitter {
|
|
|
4756
5072
|
errorEvent: events$2.error
|
|
4757
5073
|
};
|
|
4758
5074
|
}
|
|
4759
|
-
async #executeSql(sql) {
|
|
4760
|
-
const started = Date.now();
|
|
4761
|
-
const result = unwrapSQLResult(await this.#db.executeSql(sql));
|
|
4762
|
-
const elapsed = (Date.now() - started) / 1e3;
|
|
4763
|
-
if (elapsed > WARNINGS.SLOW_QUERY.seconds || this.#config.__test__warn_slow_query) {
|
|
4764
|
-
await emitAndPersistWarning(
|
|
4765
|
-
this.#warningContext,
|
|
4766
|
-
WARNING_TYPES.SLOW_QUERY,
|
|
4767
|
-
WARNINGS.SLOW_QUERY.message,
|
|
4768
|
-
{ elapsed, sql }
|
|
4769
|
-
);
|
|
4770
|
-
}
|
|
4771
|
-
return result;
|
|
4772
|
-
}
|
|
4773
5075
|
async #executeQuery(query2) {
|
|
5076
|
+
if (typeof query2 === "string") {
|
|
5077
|
+
query2 = { text: query2, values: [] };
|
|
5078
|
+
}
|
|
4774
5079
|
const started = Date.now();
|
|
4775
5080
|
const result = unwrapSQLResult(await this.#db.executeSql(query2.text, query2.values));
|
|
4776
5081
|
const elapsed = (Date.now() - started) / 1e3;
|
|
@@ -4792,6 +5097,9 @@ class Boss extends EventEmitter {
|
|
|
4792
5097
|
throw new Error(this.#config.__test__throw_maint);
|
|
4793
5098
|
}
|
|
4794
5099
|
this.#maintaining = true;
|
|
5100
|
+
if (this.#config.__test__delay_maint_ms) {
|
|
5101
|
+
await delay(this.#config.__test__delay_maint_ms);
|
|
5102
|
+
}
|
|
4795
5103
|
const queues = await this.#manager.getQueues();
|
|
4796
5104
|
!this.#stopped && await this.supervise(queues);
|
|
4797
5105
|
!this.#stopped && await this.#maintainWarnings();
|
|
@@ -4806,7 +5114,7 @@ class Boss extends EventEmitter {
|
|
|
4806
5114
|
return;
|
|
4807
5115
|
}
|
|
4808
5116
|
const sql = deleteOldWarnings(this.#config.schema, this.#config.warningRetentionDays);
|
|
4809
|
-
await this.#
|
|
5117
|
+
await this.#executeQuery(sql);
|
|
4810
5118
|
}
|
|
4811
5119
|
async supervise(value) {
|
|
4812
5120
|
let queues;
|
|
@@ -4821,6 +5129,9 @@ class Boss extends EventEmitter {
|
|
|
4821
5129
|
acc[table].queues.push(q);
|
|
4822
5130
|
return acc;
|
|
4823
5131
|
}, {});
|
|
5132
|
+
const heartbeatQueueNames = new Set(
|
|
5133
|
+
queues.filter((q) => q.heartbeatSeconds != null).map((q) => q.name)
|
|
5134
|
+
);
|
|
4824
5135
|
for (const queueGroup of Object.values(queueGroups)) {
|
|
4825
5136
|
if (this.#stopping) return;
|
|
4826
5137
|
const { table, queues: queues2 } = queueGroup;
|
|
@@ -4828,12 +5139,12 @@ class Boss extends EventEmitter {
|
|
|
4828
5139
|
while (names.length) {
|
|
4829
5140
|
if (this.#stopping) return;
|
|
4830
5141
|
const chunk = names.splice(0, 100);
|
|
4831
|
-
await this.#monitor(table, chunk);
|
|
5142
|
+
await this.#monitor(table, chunk, heartbeatQueueNames);
|
|
4832
5143
|
await this.#maintain(table, chunk);
|
|
4833
5144
|
}
|
|
4834
5145
|
}
|
|
4835
5146
|
}
|
|
4836
|
-
async #monitor(table, names) {
|
|
5147
|
+
async #monitor(table, names, heartbeatQueueNames) {
|
|
4837
5148
|
if (this.#stopping) return;
|
|
4838
5149
|
const command = trySetQueueMonitorTime(
|
|
4839
5150
|
this.#config.schema,
|
|
@@ -4845,7 +5156,7 @@ class Boss extends EventEmitter {
|
|
|
4845
5156
|
if (rows.length) {
|
|
4846
5157
|
const queues = rows.map((q) => q.name);
|
|
4847
5158
|
const cacheStatsSql = cacheQueueStats(this.#config.schema, table, queues);
|
|
4848
|
-
const { rows: rowsCacheStats } = await this.#
|
|
5159
|
+
const { rows: rowsCacheStats } = await this.#executeQuery(cacheStatsSql);
|
|
4849
5160
|
if (this.#stopping) return;
|
|
4850
5161
|
const warnings2 = rowsCacheStats.filter((i) => i.queuedCount > (i.warningQueueSize || WARNINGS.LARGE_QUEUE.size));
|
|
4851
5162
|
for (const warning of warnings2) {
|
|
@@ -4857,7 +5168,13 @@ class Boss extends EventEmitter {
|
|
|
4857
5168
|
);
|
|
4858
5169
|
}
|
|
4859
5170
|
const sql = failJobsByTimeout(this.#config.schema, table, queues);
|
|
4860
|
-
await this.#
|
|
5171
|
+
await this.#executeQuery(sql);
|
|
5172
|
+
if (this.#stopping) return;
|
|
5173
|
+
const heartbeatQueues = queues.filter((q) => heartbeatQueueNames.has(q));
|
|
5174
|
+
if (heartbeatQueues.length) {
|
|
5175
|
+
const heartbeatSql = failJobsByHeartbeat(this.#config.schema, table, heartbeatQueues);
|
|
5176
|
+
await this.#executeQuery(heartbeatSql);
|
|
5177
|
+
}
|
|
4861
5178
|
}
|
|
4862
5179
|
}
|
|
4863
5180
|
async #maintain(table, names) {
|
|
@@ -4872,7 +5189,7 @@ class Boss extends EventEmitter {
|
|
|
4872
5189
|
if (rows.length) {
|
|
4873
5190
|
const queues = rows.map((q) => q.name);
|
|
4874
5191
|
const sql = deletion(this.#config.schema, table, queues);
|
|
4875
|
-
await this.#
|
|
5192
|
+
await this.#executeQuery(sql);
|
|
4876
5193
|
}
|
|
4877
5194
|
}
|
|
4878
5195
|
}
|
|
@@ -4894,6 +5211,9 @@ class Bam extends EventEmitter {
|
|
|
4894
5211
|
this.#stopped = true;
|
|
4895
5212
|
this.#working = false;
|
|
4896
5213
|
}
|
|
5214
|
+
get working() {
|
|
5215
|
+
return this.#working;
|
|
5216
|
+
}
|
|
4897
5217
|
async start() {
|
|
4898
5218
|
if (!this.#stopped) return;
|
|
4899
5219
|
this.#stopped = false;
|
|
@@ -4910,6 +5230,9 @@ class Bam extends EventEmitter {
|
|
|
4910
5230
|
clearInterval(this.#pollInterval);
|
|
4911
5231
|
this.#pollInterval = void 0;
|
|
4912
5232
|
}
|
|
5233
|
+
while (this.#working) {
|
|
5234
|
+
await delay(10);
|
|
5235
|
+
}
|
|
4913
5236
|
}
|
|
4914
5237
|
async #onPoll() {
|
|
4915
5238
|
if (this.#stopped || this.#working || !this.#config.migrate) return;
|
|
@@ -4918,6 +5241,9 @@ class Bam extends EventEmitter {
|
|
|
4918
5241
|
if (this.#config.__test__throw_bam) {
|
|
4919
5242
|
throw new Error(this.#config.__test__throw_bam);
|
|
4920
5243
|
}
|
|
5244
|
+
if (this.#config.__test__delay_bam_ms) {
|
|
5245
|
+
await delay(this.#config.__test__delay_bam_ms);
|
|
5246
|
+
}
|
|
4921
5247
|
const sql = trySetBamTime(
|
|
4922
5248
|
this.#config.schema,
|
|
4923
5249
|
this.#config.bamIntervalSeconds
|
|
@@ -5187,6 +5513,9 @@ class PgBoss extends EventEmitter {
|
|
|
5187
5513
|
fail(name, id, data, options) {
|
|
5188
5514
|
return this.#manager.fail(name, id, data, options);
|
|
5189
5515
|
}
|
|
5516
|
+
touch(name, id, options) {
|
|
5517
|
+
return this.#manager.touch(name, id, options);
|
|
5518
|
+
}
|
|
5190
5519
|
/**
|
|
5191
5520
|
* @deprecated Use findJobs() instead
|
|
5192
5521
|
*/
|
|
@@ -5217,6 +5546,15 @@ class PgBoss extends EventEmitter {
|
|
|
5217
5546
|
getQueueStats(name) {
|
|
5218
5547
|
return this.#manager.getQueueStats(name);
|
|
5219
5548
|
}
|
|
5549
|
+
isMaintaining() {
|
|
5550
|
+
return this.#boss.maintaining;
|
|
5551
|
+
}
|
|
5552
|
+
isBamWorking() {
|
|
5553
|
+
return this.#bam.working;
|
|
5554
|
+
}
|
|
5555
|
+
isCheckingSkew() {
|
|
5556
|
+
return this.#timekeeper.checkingSkew;
|
|
5557
|
+
}
|
|
5220
5558
|
supervise(name) {
|
|
5221
5559
|
return this.#boss.supervise(name);
|
|
5222
5560
|
}
|
|
@@ -9559,10 +9897,10 @@ const route11 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePrope
|
|
|
9559
9897
|
default: warnings,
|
|
9560
9898
|
loader
|
|
9561
9899
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
9562
|
-
const serverManifest = { "entry": { "module": "/assets/entry.client-
|
|
9900
|
+
const serverManifest = { "entry": { "module": "/assets/entry.client-DXZUROTm.js", "imports": ["/assets/chunk-UVKPFVEO-YfSfkVr_.js", "/assets/index-DuhoQwUK.js"], "css": [] }, "routes": { "root": { "id": "root", "parentId": void 0, "path": "", "index": void 0, "caseSensitive": void 0, "hasAction": false, "hasLoader": true, "hasClientAction": false, "hasClientLoader": false, "hasClientMiddleware": false, "hasDefaultExport": true, "hasErrorBoundary": true, "module": "/assets/root-DDqOT0vL.js", "imports": ["/assets/chunk-UVKPFVEO-YfSfkVr_.js", "/assets/index-DuhoQwUK.js", "/assets/db-link-CU7IJqbq.js", "/assets/createLucideIcon-Bt-yXILq.js", "/assets/MenuTrigger-CoRd-BqL.js", "/assets/useOpenInteractionType-mgYMZAa8.js"], "css": ["/assets/root-Bpb4WtY4.css"], "clientActionModule": void 0, "clientLoaderModule": void 0, "clientMiddlewareModule": void 0, "hydrateFallbackModule": void 0 }, "routes/_index": { "id": "routes/_index", "parentId": "root", "path": void 0, "index": true, "caseSensitive": void 0, "hasAction": false, "hasLoader": true, "hasClientAction": false, "hasClientLoader": false, "hasClientMiddleware": false, "hasDefaultExport": true, "hasErrorBoundary": true, "module": "/assets/_index-BTx7NRR8.js", "imports": ["/assets/chunk-UVKPFVEO-YfSfkVr_.js", "/assets/db-link-CU7IJqbq.js", "/assets/button-Ba8FWhqs.js", "/assets/badge-DBD4CzAv.js", "/assets/table-Au2E5mnP.js", "/assets/error-card-D-uZRy_l.js"], "css": [], "clientActionModule": void 0, "clientLoaderModule": void 0, "clientMiddlewareModule": void 0, "hydrateFallbackModule": void 0 }, "routes/jobs": { "id": "routes/jobs", "parentId": "root", "path": "jobs", "index": void 0, "caseSensitive": void 0, "hasAction": false, "hasLoader": true, "hasClientAction": false, "hasClientLoader": false, "hasClientMiddleware": false, "hasDefaultExport": true, "hasErrorBoundary": true, "module": "/assets/jobs-ouYjIGAi.js", "imports": ["/assets/chunk-UVKPFVEO-YfSfkVr_.js", "/assets/db-link-CU7IJqbq.js", "/assets/button-Ba8FWhqs.js", "/assets/badge-DBD4CzAv.js", "/assets/table-Au2E5mnP.js", "/assets/pagination-BItl293Q.js", "/assets/filter-select-Tk_CBvrn.js", "/assets/error-card-D-uZRy_l.js"], "css": [], "clientActionModule": void 0, "clientLoaderModule": void 0, "clientMiddlewareModule": void 0, "hydrateFallbackModule": void 0 }, "routes/queues._index": { "id": "routes/queues._index", "parentId": "root", "path": "queues", "index": void 0, "caseSensitive": void 0, "hasAction": false, "hasLoader": true, "hasClientAction": false, "hasClientLoader": false, "hasClientMiddleware": false, "hasDefaultExport": true, "hasErrorBoundary": true, "module": "/assets/queues._index-_ID9kaow.js", "imports": ["/assets/chunk-UVKPFVEO-YfSfkVr_.js", "/assets/db-link-CU7IJqbq.js", "/assets/button-Ba8FWhqs.js", "/assets/badge-DBD4CzAv.js", "/assets/filter-select-Tk_CBvrn.js", "/assets/table-Au2E5mnP.js"], "css": [], "clientActionModule": void 0, "clientLoaderModule": void 0, "clientMiddlewareModule": void 0, "hydrateFallbackModule": void 0 }, "routes/queues.create": { "id": "routes/queues.create", "parentId": "root", "path": "queues/create", "index": void 0, "caseSensitive": void 0, "hasAction": true, "hasLoader": true, "hasClientAction": false, "hasClientLoader": false, "hasClientMiddleware": false, "hasDefaultExport": true, "hasErrorBoundary": true, "module": "/assets/queues.create-CmVW5UVm.js", "imports": ["/assets/chunk-UVKPFVEO-YfSfkVr_.js", "/assets/db-link-CU7IJqbq.js", "/assets/button-Ba8FWhqs.js", "/assets/chevron-down-CYa4FYmp.js", "/assets/error-card-D-uZRy_l.js", "/assets/createLucideIcon-Bt-yXILq.js"], "css": [], "clientActionModule": void 0, "clientLoaderModule": void 0, "clientMiddlewareModule": void 0, "hydrateFallbackModule": void 0 }, "routes/queues.$name": { "id": "routes/queues.$name", "parentId": "root", "path": "queues/:name", "index": void 0, "caseSensitive": void 0, "hasAction": true, "hasLoader": true, "hasClientAction": false, "hasClientLoader": false, "hasClientMiddleware": false, "hasDefaultExport": true, "hasErrorBoundary": true, "module": "/assets/queues._name-DwdbQND-.js", "imports": ["/assets/chunk-UVKPFVEO-YfSfkVr_.js", "/assets/db-link-CU7IJqbq.js", "/assets/button-Ba8FWhqs.js", "/assets/badge-DBD4CzAv.js", "/assets/table-Au2E5mnP.js", "/assets/pagination-BItl293Q.js", "/assets/filter-select-Tk_CBvrn.js", "/assets/dialog-Dkx42Rkd.js", "/assets/error-card-D-uZRy_l.js", "/assets/chevron-down-CYa4FYmp.js", "/assets/createLucideIcon-Bt-yXILq.js", "/assets/MenuTrigger-CoRd-BqL.js", "/assets/useOpenInteractionType-mgYMZAa8.js", "/assets/index-DuhoQwUK.js"], "css": [], "clientActionModule": void 0, "clientLoaderModule": void 0, "clientMiddlewareModule": void 0, "hydrateFallbackModule": void 0 }, "routes/queues.$name.jobs.$jobId": { "id": "routes/queues.$name.jobs.$jobId", "parentId": "root", "path": "queues/:name/jobs/:jobId", "index": void 0, "caseSensitive": void 0, "hasAction": true, "hasLoader": true, "hasClientAction": false, "hasClientLoader": false, "hasClientMiddleware": false, "hasDefaultExport": true, "hasErrorBoundary": true, "module": "/assets/queues._name.jobs._jobId-DrgG3VBb.js", "imports": ["/assets/chunk-UVKPFVEO-YfSfkVr_.js", "/assets/db-link-CU7IJqbq.js", "/assets/button-Ba8FWhqs.js", "/assets/badge-DBD4CzAv.js", "/assets/dialog-Dkx42Rkd.js", "/assets/error-card-D-uZRy_l.js", "/assets/createLucideIcon-Bt-yXILq.js", "/assets/useOpenInteractionType-mgYMZAa8.js", "/assets/index-DuhoQwUK.js"], "css": [], "clientActionModule": void 0, "clientLoaderModule": void 0, "clientMiddlewareModule": void 0, "hydrateFallbackModule": void 0 }, "routes/schedules": { "id": "routes/schedules", "parentId": "root", "path": "schedules", "index": void 0, "caseSensitive": void 0, "hasAction": false, "hasLoader": true, "hasClientAction": false, "hasClientLoader": false, "hasClientMiddleware": false, "hasDefaultExport": true, "hasErrorBoundary": true, "module": "/assets/schedules-B6ixYsvz.js", "imports": ["/assets/chunk-UVKPFVEO-YfSfkVr_.js", "/assets/db-link-CU7IJqbq.js", "/assets/button-Ba8FWhqs.js", "/assets/table-Au2E5mnP.js", "/assets/pagination-BItl293Q.js", "/assets/error-card-D-uZRy_l.js"], "css": [], "clientActionModule": void 0, "clientLoaderModule": void 0, "clientMiddlewareModule": void 0, "hydrateFallbackModule": void 0 }, "routes/schedules.$name.$key": { "id": "routes/schedules.$name.$key", "parentId": "root", "path": "schedules/:name/:key", "index": void 0, "caseSensitive": void 0, "hasAction": true, "hasLoader": true, "hasClientAction": false, "hasClientLoader": false, "hasClientMiddleware": false, "hasDefaultExport": true, "hasErrorBoundary": true, "module": "/assets/schedules._name._key-CXTVKoOc.js", "imports": ["/assets/chunk-UVKPFVEO-YfSfkVr_.js", "/assets/db-link-CU7IJqbq.js", "/assets/button-Ba8FWhqs.js", "/assets/dialog-Dkx42Rkd.js", "/assets/error-card-D-uZRy_l.js", "/assets/createLucideIcon-Bt-yXILq.js", "/assets/useOpenInteractionType-mgYMZAa8.js", "/assets/index-DuhoQwUK.js"], "css": [], "clientActionModule": void 0, "clientLoaderModule": void 0, "clientMiddlewareModule": void 0, "hydrateFallbackModule": void 0 }, "routes/schedules.new": { "id": "routes/schedules.new", "parentId": "root", "path": "schedules/new", "index": void 0, "caseSensitive": void 0, "hasAction": true, "hasLoader": true, "hasClientAction": false, "hasClientLoader": false, "hasClientMiddleware": false, "hasDefaultExport": true, "hasErrorBoundary": true, "module": "/assets/schedules.new-Dmasri9v.js", "imports": ["/assets/chunk-UVKPFVEO-YfSfkVr_.js", "/assets/db-link-CU7IJqbq.js", "/assets/button-Ba8FWhqs.js", "/assets/error-card-D-uZRy_l.js"], "css": [], "clientActionModule": void 0, "clientLoaderModule": void 0, "clientMiddlewareModule": void 0, "hydrateFallbackModule": void 0 }, "routes/send": { "id": "routes/send", "parentId": "root", "path": "send", "index": void 0, "caseSensitive": void 0, "hasAction": true, "hasLoader": true, "hasClientAction": false, "hasClientLoader": false, "hasClientMiddleware": false, "hasDefaultExport": true, "hasErrorBoundary": true, "module": "/assets/send-CqR34Z50.js", "imports": ["/assets/chunk-UVKPFVEO-YfSfkVr_.js", "/assets/db-link-CU7IJqbq.js", "/assets/button-Ba8FWhqs.js", "/assets/error-card-D-uZRy_l.js"], "css": [], "clientActionModule": void 0, "clientLoaderModule": void 0, "clientMiddlewareModule": void 0, "hydrateFallbackModule": void 0 }, "routes/warnings": { "id": "routes/warnings", "parentId": "root", "path": "warnings", "index": void 0, "caseSensitive": void 0, "hasAction": false, "hasLoader": true, "hasClientAction": false, "hasClientLoader": false, "hasClientMiddleware": false, "hasDefaultExport": true, "hasErrorBoundary": true, "module": "/assets/warnings-Dj3qacgN.js", "imports": ["/assets/chunk-UVKPFVEO-YfSfkVr_.js", "/assets/button-Ba8FWhqs.js", "/assets/badge-DBD4CzAv.js", "/assets/table-Au2E5mnP.js", "/assets/pagination-BItl293Q.js", "/assets/filter-select-Tk_CBvrn.js", "/assets/error-card-D-uZRy_l.js", "/assets/db-link-CU7IJqbq.js"], "css": [], "clientActionModule": void 0, "clientLoaderModule": void 0, "clientMiddlewareModule": void 0, "hydrateFallbackModule": void 0 } }, "url": "/assets/manifest-72f6b3e9.js", "version": "72f6b3e9", "sri": void 0 };
|
|
9563
9901
|
const assetsBuildDirectory = "build/client";
|
|
9564
9902
|
const basename = "/";
|
|
9565
|
-
const future = { "unstable_optimizeDeps": false, "unstable_subResourceIntegrity": false, "unstable_trailingSlashAwareDataRequests": false, "v8_middleware": false, "v8_splitRouteModules": false, "v8_viteEnvironmentApi": false };
|
|
9903
|
+
const future = { "unstable_optimizeDeps": false, "unstable_passThroughRequests": false, "unstable_subResourceIntegrity": false, "unstable_trailingSlashAwareDataRequests": false, "unstable_previewServerPrerendering": false, "v8_middleware": false, "v8_splitRouteModules": false, "v8_viteEnvironmentApi": false };
|
|
9566
9904
|
const ssr = true;
|
|
9567
9905
|
const isSpaMode = false;
|
|
9568
9906
|
const prerender = [];
|