pg-boss 12.35.1 → 12.37.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/dist/attorney.d.ts.map +1 -1
- package/dist/attorney.js +26 -0
- package/dist/boss.d.ts.map +1 -1
- package/dist/boss.js +35 -4
- package/dist/cli.js +8 -2
- package/dist/contractor.d.ts +1 -0
- package/dist/contractor.d.ts.map +1 -1
- package/dist/contractor.js +4 -0
- package/dist/db.d.ts +1 -0
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +14 -3
- package/dist/index.d.ts +11 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +88 -9
- package/dist/latency.d.ts +15 -0
- package/dist/latency.d.ts.map +1 -0
- package/dist/latency.js +45 -0
- package/dist/manager.d.ts.map +1 -1
- package/dist/manager.js +296 -75
- package/dist/migrationStore.d.ts.map +1 -1
- package/dist/migrationStore.js +194 -0
- package/dist/nurse.d.ts +20 -0
- package/dist/nurse.d.ts.map +1 -0
- package/dist/nurse.js +287 -0
- package/dist/plans.d.ts +27 -2
- package/dist/plans.d.ts.map +1 -1
- package/dist/plans.js +556 -55
- package/dist/registrar.d.ts +16 -0
- package/dist/registrar.d.ts.map +1 -0
- package/dist/registrar.js +226 -0
- package/dist/schema.json +514 -2
- package/dist/telemetry.d.ts +65 -0
- package/dist/telemetry.d.ts.map +1 -0
- package/dist/telemetry.js +349 -0
- package/dist/timekeeper.d.ts +4 -1
- package/dist/timekeeper.d.ts.map +1 -1
- package/dist/timekeeper.js +22 -5
- package/dist/types.d.ts +213 -8
- package/dist/types.d.ts.map +1 -1
- package/dist/worker.d.ts +1 -0
- package/dist/worker.d.ts.map +1 -1
- package/dist/worker.js +2 -0
- package/package.json +14 -5
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migrationStore.d.ts","sourceRoot":"","sources":["../src/migrationStore.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AAKnC,UAAU,cAAc;IACtB,WAAW,CAAC,EAAE,OAAO,CAAA;IAKrB,eAAe,CAAC,EAAE,KAAK,CAAC,kBAAkB,EAAE,CAAA;CAC7C;AAoGD,UAAU,iBAAiB;IACzB,GAAG,EAAE,MAAM,CAAA;IACX,UAAU,EAAE,MAAM,EAAE,CAAA;CACrB;AASD,iBAAS,QAAQ,CAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,KAAK,CAAC,SAAS,EAAE,EAAE,eAAe,CAAC,EAAE,OAAO,UAsB5G;AAED,iBAAS,IAAI,CAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,KAAK,CAAC,SAAS,EAAE,EAAE,eAAe,CAAC,EAAE,OAAO,UAQxG;AAKD,iBAAS,eAAe,CAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,KAAK,CAAC,SAAS,EAAE,EAAE,eAAe,CAAC,EAAE,OAAO,EAAE,OAAO,GAAE,cAAmB,GAAG,iBAAiB,CAiDrK;AAKD,iBAAS,OAAO,CAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,KAAK,CAAC,SAAS,EAAE,EAAE,eAAe,CAAC,EAAE,OAAO,EAAE,OAAO,GAAE,cAAmB,UAIzI;
|
|
1
|
+
{"version":3,"file":"migrationStore.d.ts","sourceRoot":"","sources":["../src/migrationStore.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AAKnC,UAAU,cAAc;IACtB,WAAW,CAAC,EAAE,OAAO,CAAA;IAKrB,eAAe,CAAC,EAAE,KAAK,CAAC,kBAAkB,EAAE,CAAA;CAC7C;AAoGD,UAAU,iBAAiB;IACzB,GAAG,EAAE,MAAM,CAAA;IACX,UAAU,EAAE,MAAM,EAAE,CAAA;CACrB;AASD,iBAAS,QAAQ,CAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,KAAK,CAAC,SAAS,EAAE,EAAE,eAAe,CAAC,EAAE,OAAO,UAsB5G;AAED,iBAAS,IAAI,CAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,KAAK,CAAC,SAAS,EAAE,EAAE,eAAe,CAAC,EAAE,OAAO,UAQxG;AAKD,iBAAS,eAAe,CAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,KAAK,CAAC,SAAS,EAAE,EAAE,eAAe,CAAC,EAAE,OAAO,EAAE,OAAO,GAAE,cAAmB,GAAG,iBAAiB,CAiDrK;AAKD,iBAAS,OAAO,CAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,KAAK,CAAC,SAAS,EAAE,EAAE,eAAe,CAAC,EAAE,OAAO,EAAE,OAAO,GAAE,cAAmB,UAIzI;AA6tCD,iBAAS,aAAa,CAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAE9C;AAID,iBAAS,eAAe,CAAE,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,0BAA0B,EAAE,QAAQ,GAAG,qBAAqB,GAAG,mBAAmB,GAAG,qBAAqB,CAAC,GAAG,KAAK,CAAC,SAAS,EAAE,CAE3K;AAOD,iBAAS,MAAM,CAAE,MAAM,EAAE,MAAM,EAAE,cAAc,UAAQ,EAAE,UAAU,UAAQ,EAAE,mBAAmB,UAAQ,GAAG,KAAK,CAAC,SAAS,EAAE,CAivB3H;AAED,OAAO,EACL,QAAQ,EACR,IAAI,EACJ,OAAO,EACP,eAAe,EACf,MAAM,EACN,eAAe,EACf,aAAa,GACd,CAAA"}
|
package/dist/migrationStore.js
CHANGED
|
@@ -1087,6 +1087,99 @@ const createQueueFn = {
|
|
|
1087
1087
|
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);
|
|
1088
1088
|
END IF;
|
|
1089
1089
|
|
|
1090
|
+
EXECUTE format('ALTER TABLE ${schema}.%I ADD CONSTRAINT cjc CHECK (name=%L)', tablename, queue_name);
|
|
1091
|
+
EXECUTE format('ALTER TABLE ${schema}.job ATTACH PARTITION ${schema}.%I FOR VALUES IN (%L)', tablename, queue_name);
|
|
1092
|
+
END;
|
|
1093
|
+
$$
|
|
1094
|
+
LANGUAGE plpgsql;
|
|
1095
|
+
`,
|
|
1096
|
+
45: (schema) => `
|
|
1097
|
+
CREATE OR REPLACE FUNCTION ${schema}.create_queue(queue_name text, options jsonb)
|
|
1098
|
+
RETURNS VOID AS
|
|
1099
|
+
$$
|
|
1100
|
+
DECLARE
|
|
1101
|
+
tablename varchar := CASE WHEN options->>'partition' = 'true'
|
|
1102
|
+
THEN 'j' || encode(sha224(queue_name::bytea), 'hex')
|
|
1103
|
+
ELSE 'job_common'
|
|
1104
|
+
END;
|
|
1105
|
+
queue_created_on timestamptz;
|
|
1106
|
+
BEGIN
|
|
1107
|
+
|
|
1108
|
+
WITH q as (
|
|
1109
|
+
INSERT INTO ${schema}.queue (
|
|
1110
|
+
name,
|
|
1111
|
+
policy,
|
|
1112
|
+
retry_limit,
|
|
1113
|
+
retry_delay,
|
|
1114
|
+
retry_backoff,
|
|
1115
|
+
retry_delay_max,
|
|
1116
|
+
expire_seconds,
|
|
1117
|
+
retention_seconds,
|
|
1118
|
+
deletion_seconds,
|
|
1119
|
+
warning_queued,
|
|
1120
|
+
dead_letter,
|
|
1121
|
+
partition,
|
|
1122
|
+
table_name,
|
|
1123
|
+
heartbeat_seconds,
|
|
1124
|
+
notify,
|
|
1125
|
+
created_on,
|
|
1126
|
+
updated_on
|
|
1127
|
+
)
|
|
1128
|
+
VALUES (
|
|
1129
|
+
queue_name,
|
|
1130
|
+
options->>'policy',
|
|
1131
|
+
COALESCE((options->>'retryLimit')::int, 2),
|
|
1132
|
+
COALESCE((options->>'retryDelay')::int, 0),
|
|
1133
|
+
COALESCE((options->>'retryBackoff')::bool, false),
|
|
1134
|
+
(options->>'retryDelayMax')::int,
|
|
1135
|
+
COALESCE((options->>'expireInSeconds')::int, 900),
|
|
1136
|
+
COALESCE((options->>'retentionSeconds')::int, 1209600),
|
|
1137
|
+
COALESCE((options->>'deleteAfterSeconds')::int, 604800),
|
|
1138
|
+
COALESCE((options->>'warningQueueSize')::int, 0),
|
|
1139
|
+
options->>'deadLetter',
|
|
1140
|
+
COALESCE((options->>'partition')::bool, false),
|
|
1141
|
+
tablename,
|
|
1142
|
+
(options->>'heartbeatSeconds')::int,
|
|
1143
|
+
COALESCE((options->>'notify')::bool, false),
|
|
1144
|
+
${schema}.job_now(),
|
|
1145
|
+
${schema}.job_now()
|
|
1146
|
+
)
|
|
1147
|
+
ON CONFLICT DO NOTHING
|
|
1148
|
+
RETURNING created_on
|
|
1149
|
+
)
|
|
1150
|
+
SELECT created_on into queue_created_on from q;
|
|
1151
|
+
|
|
1152
|
+
IF queue_created_on IS NULL OR options->>'partition' IS DISTINCT FROM 'true' THEN
|
|
1153
|
+
RETURN;
|
|
1154
|
+
END IF;
|
|
1155
|
+
|
|
1156
|
+
EXECUTE format('CREATE TABLE ${schema}.%I (LIKE ${schema}.job INCLUDING DEFAULTS)', tablename);
|
|
1157
|
+
|
|
1158
|
+
EXECUTE ${schema}.job_table_format($cmd$ALTER TABLE ${schema}.job ADD PRIMARY KEY (name, id)$cmd$, tablename);
|
|
1159
|
+
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);
|
|
1160
|
+
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);
|
|
1161
|
+
|
|
1162
|
+
EXECUTE ${schema}.job_table_format($cmd$CREATE INDEX job_i11 ON ${schema}.job (name, priority DESC, created_on, start_after) WHERE state < 'active' AND NOT blocked$cmd$, tablename);
|
|
1163
|
+
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);
|
|
1164
|
+
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);
|
|
1165
|
+
EXECUTE ${schema}.job_table_format($cmd$CREATE INDEX job_i9 ON ${schema}.job (name, id) WHERE blocking AND state = 'completed'$cmd$, tablename);
|
|
1166
|
+
EXECUTE ${schema}.job_table_format($cmd$CREATE INDEX job_i12 ON ${schema}.job (source_root_id) WHERE source_root_id IS NOT NULL$cmd$, tablename);
|
|
1167
|
+
EXECUTE ${schema}.job_table_format($cmd$CREATE UNIQUE INDEX job_i13 ON ${schema}.job (name, singleton_key) WHERE state = 'created' AND upsert_by_key$cmd$, tablename);
|
|
1168
|
+
|
|
1169
|
+
IF options->>'policy' = 'short' THEN
|
|
1170
|
+
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);
|
|
1171
|
+
ELSIF options->>'policy' = 'singleton' THEN
|
|
1172
|
+
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);
|
|
1173
|
+
ELSIF options->>'policy' = 'stately' THEN
|
|
1174
|
+
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);
|
|
1175
|
+
ELSIF options->>'policy' = 'exclusive' THEN
|
|
1176
|
+
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);
|
|
1177
|
+
ELSIF options->>'policy' = 'key_strict_fifo' THEN
|
|
1178
|
+
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);
|
|
1179
|
+
EXECUTE ${schema}.job_table_format($cmd$CREATE INDEX job_i10 ON ${schema}.job (name, singleton_key, state DESC, created_on, id) INCLUDE (start_after) WHERE state < 'active' AND NOT blocked AND policy = 'key_strict_fifo'$cmd$, tablename);
|
|
1180
|
+
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);
|
|
1181
|
+
END IF;
|
|
1182
|
+
|
|
1090
1183
|
EXECUTE format('ALTER TABLE ${schema}.%I ADD CONSTRAINT cjc CHECK (name=%L)', tablename, queue_name);
|
|
1091
1184
|
EXECUTE format('ALTER TABLE ${schema}.job ATTACH PARTITION ${schema}.%I FOR VALUES IN (%L)', tablename, queue_name);
|
|
1092
1185
|
END;
|
|
@@ -1963,6 +2056,107 @@ AS $function$
|
|
|
1963
2056
|
DROP COLUMN source_output,
|
|
1964
2057
|
DROP COLUMN source_root_id`
|
|
1965
2058
|
]
|
|
2059
|
+
},
|
|
2060
|
+
{
|
|
2061
|
+
release: '12.36.0',
|
|
2062
|
+
version: 44,
|
|
2063
|
+
previous: 43,
|
|
2064
|
+
// The instance table starts empty: each instance registers on its next start().
|
|
2065
|
+
// blocked_count's constant default adds it without a table rewrite, and existing queues read 0
|
|
2066
|
+
// until the next monitor pass counts them. It goes on the queue row only, not queue_stats, so
|
|
2067
|
+
// the covering index on queue_stats needs no rebuild.
|
|
2068
|
+
// The histogram and ready_oldest_seconds columns are nullable with no default, like the v43
|
|
2069
|
+
// deltas, so no statement rewrites a table, and a snapshot captured before them reads as not
|
|
2070
|
+
// counted rather than as a queue with no waits.
|
|
2071
|
+
// trace_context is nullable with no default too, so adding it rewrites no rows.
|
|
2072
|
+
install: [
|
|
2073
|
+
/* eslint-disable no-restricted-syntax -- column defaults stay on the real clock: every pg-boss write names its timestamps through job_now() */
|
|
2074
|
+
`CREATE TABLE ${schema}.instance (
|
|
2075
|
+
id uuid PRIMARY KEY,
|
|
2076
|
+
name text,
|
|
2077
|
+
host text NOT NULL,
|
|
2078
|
+
pid int NOT NULL,
|
|
2079
|
+
version text NOT NULL,
|
|
2080
|
+
node_version text NOT NULL,
|
|
2081
|
+
application_name text,
|
|
2082
|
+
heartbeat_seconds int NOT NULL,
|
|
2083
|
+
supervise bool NOT NULL,
|
|
2084
|
+
schedule bool NOT NULL,
|
|
2085
|
+
migrate bool NOT NULL,
|
|
2086
|
+
persist_queue_stats bool NOT NULL,
|
|
2087
|
+
persist_warnings bool NOT NULL,
|
|
2088
|
+
pool_max int,
|
|
2089
|
+
pool_total int,
|
|
2090
|
+
pool_idle int,
|
|
2091
|
+
pool_waiting int,
|
|
2092
|
+
workers jsonb NOT NULL DEFAULT '[]'::jsonb,
|
|
2093
|
+
metrics jsonb,
|
|
2094
|
+
config jsonb NOT NULL DEFAULT '{}'::jsonb,
|
|
2095
|
+
crash_restarts int NOT NULL DEFAULT 0,
|
|
2096
|
+
crash_restarts_since timestamptz,
|
|
2097
|
+
started_on timestamptz NOT NULL DEFAULT now(),
|
|
2098
|
+
heartbeat_on timestamptz NOT NULL DEFAULT now(),
|
|
2099
|
+
stopped_on timestamptz
|
|
2100
|
+
)`,
|
|
2101
|
+
/* eslint-enable no-restricted-syntax */
|
|
2102
|
+
`ALTER TABLE ${schema}.queue
|
|
2103
|
+
ADD COLUMN blocked_count int NOT NULL DEFAULT 0,
|
|
2104
|
+
ADD COLUMN wait_bins int[],
|
|
2105
|
+
ADD COLUMN run_bins int[],
|
|
2106
|
+
ADD COLUMN ready_oldest_seconds int`,
|
|
2107
|
+
`ALTER TABLE ${schema}.queue_stats
|
|
2108
|
+
ADD COLUMN wait_bins int[],
|
|
2109
|
+
ADD COLUMN run_bins int[],
|
|
2110
|
+
ADD COLUMN ready_oldest_seconds int`,
|
|
2111
|
+
`ALTER TABLE ${schema}.job ADD COLUMN IF NOT EXISTS trace_context jsonb`
|
|
2112
|
+
],
|
|
2113
|
+
uninstall: [
|
|
2114
|
+
`DROP TABLE ${schema}.instance`,
|
|
2115
|
+
`ALTER TABLE ${schema}.queue
|
|
2116
|
+
DROP COLUMN blocked_count,
|
|
2117
|
+
DROP COLUMN wait_bins,
|
|
2118
|
+
DROP COLUMN run_bins,
|
|
2119
|
+
DROP COLUMN ready_oldest_seconds`,
|
|
2120
|
+
`ALTER TABLE ${schema}.queue_stats
|
|
2121
|
+
DROP COLUMN wait_bins,
|
|
2122
|
+
DROP COLUMN run_bins,
|
|
2123
|
+
DROP COLUMN ready_oldest_seconds`,
|
|
2124
|
+
`ALTER TABLE ${schema}.job DROP COLUMN trace_context`
|
|
2125
|
+
]
|
|
2126
|
+
},
|
|
2127
|
+
{
|
|
2128
|
+
release: '12.37.0',
|
|
2129
|
+
version: 45,
|
|
2130
|
+
previous: 44,
|
|
2131
|
+
// upsert_by_key is nullable with no default, so adding it rewrites no rows, and no existing job
|
|
2132
|
+
// carries it. job_i13 therefore starts empty and cannot fail on existing duplicates.
|
|
2133
|
+
// It is built the way v43 built job_i12: inline without partitioning, otherwise through
|
|
2134
|
+
// create_queue for new partitions and BAM, concurrently, for the tables that already exist.
|
|
2135
|
+
install: [
|
|
2136
|
+
`ALTER TABLE ${schema}.job ADD COLUMN IF NOT EXISTS upsert_by_key bool`,
|
|
2137
|
+
noPartitioning
|
|
2138
|
+
? `CREATE UNIQUE INDEX job_i13 ON ${schema}.job (name, singleton_key) WHERE state = 'created' AND upsert_by_key`
|
|
2139
|
+
: createQueueFn[45](schema)
|
|
2140
|
+
],
|
|
2141
|
+
async: noPartitioning
|
|
2142
|
+
? []
|
|
2143
|
+
: [
|
|
2144
|
+
{
|
|
2145
|
+
name: 'upsert_index_build',
|
|
2146
|
+
command: `CREATE UNIQUE INDEX CONCURRENTLY IF NOT EXISTS job_i13 ON ${schema}.job (name, singleton_key) WHERE state = 'created' AND upsert_by_key`
|
|
2147
|
+
}
|
|
2148
|
+
],
|
|
2149
|
+
// The index goes before its column, and create_queue is restored first, as in v43. CASCADE because
|
|
2150
|
+
// CockroachDB will not drop a unique index without it.
|
|
2151
|
+
uninstall: [
|
|
2152
|
+
...(noPartitioning
|
|
2153
|
+
? [`DROP INDEX IF EXISTS ${schema}.job_i13 CASCADE`]
|
|
2154
|
+
: [
|
|
2155
|
+
createQueueFn[43](schema),
|
|
2156
|
+
`SELECT ${schema}.job_table_run($cmd$DROP INDEX IF EXISTS ${schema}.job_i13$cmd$)`
|
|
2157
|
+
]),
|
|
2158
|
+
`ALTER TABLE ${schema}.job DROP COLUMN upsert_by_key`
|
|
2159
|
+
]
|
|
1966
2160
|
}
|
|
1967
2161
|
];
|
|
1968
2162
|
}
|
package/dist/nurse.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type * as types from './types.ts';
|
|
2
|
+
interface Hierarchy {
|
|
3
|
+
dirs: string[];
|
|
4
|
+
}
|
|
5
|
+
export interface Cgroup {
|
|
6
|
+
version: 1 | 2;
|
|
7
|
+
cpu: Hierarchy | null;
|
|
8
|
+
memory: Hierarchy | null;
|
|
9
|
+
}
|
|
10
|
+
export declare function findCgroup(prefix?: string): Promise<Cgroup | null>;
|
|
11
|
+
export declare function countCpuList(list: string): number | null;
|
|
12
|
+
declare class Nurse {
|
|
13
|
+
#private;
|
|
14
|
+
constructor(prefix?: string);
|
|
15
|
+
start(): void;
|
|
16
|
+
stop(): void;
|
|
17
|
+
check(): Promise<types.InstanceMetrics>;
|
|
18
|
+
}
|
|
19
|
+
export default Nurse;
|
|
20
|
+
//# sourceMappingURL=nurse.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nurse.d.ts","sourceRoot":"","sources":["../src/nurse.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,KAAK,KAAK,MAAM,YAAY,CAAA;AAmBxC,UAAU,SAAS;IAGjB,IAAI,EAAE,MAAM,EAAE,CAAA;CACf;AAED,MAAM,WAAW,MAAM;IACrB,OAAO,EAAE,CAAC,GAAG,CAAC,CAAA;IACd,GAAG,EAAE,SAAS,GAAG,IAAI,CAAA;IACrB,MAAM,EAAE,SAAS,GAAG,IAAI,CAAA;CACzB;AAmDD,wBAAsB,UAAU,CAAE,MAAM,SAAK,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAkDrE;AA0ED,wBAAgB,YAAY,CAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAUzD;AAYD,cAAM,KAAK;;gBASI,MAAM,SAAK;IAIxB,KAAK;IAgBL,IAAI;IAOE,KAAK,IAAK,OAAO,CAAC,KAAK,CAAC,eAAe,CAAC;CAmF/C;AAED,eAAe,KAAK,CAAA"}
|
package/dist/nurse.js
ADDED
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import { monitorEventLoopDelay, performance } from 'node:perf_hooks';
|
|
4
|
+
import v8 from 'node:v8';
|
|
5
|
+
// Takes this process's vitals on each registry heartbeat: what it is using and what it is allowed. Inside a
|
|
6
|
+
// container the host-wide figures Node offers are the wrong ones: os.totalmem(), os.freemem(),
|
|
7
|
+
// os.loadavg() and os.cpus() describe the machine, not the container, and os.availableParallelism()
|
|
8
|
+
// ignores a CPU quota under one core (12 at --cpus=0.5) and rounds others down (1 at --cpus=1.5). So
|
|
9
|
+
// limits and container usage are read from the cgroup files this process is charged to, found through
|
|
10
|
+
// /proc/self/cgroup and /proc/self/mountinfo, which covers cgroup v1 and v2 and a private or host
|
|
11
|
+
// cgroup namespace alike. Off Linux, or where those files cannot be read, the limits fall back to the
|
|
12
|
+
// host and the container-only figures are null. Nothing here throws: a figure that cannot be read is
|
|
13
|
+
// null, and the heartbeat goes out regardless.
|
|
14
|
+
// Event loop delay is sampled on a timer of this resolution, which every sample includes and which is
|
|
15
|
+
// subtracted, so an idle loop reads close to zero.
|
|
16
|
+
const LOOP_RESOLUTION_MS = 20;
|
|
17
|
+
// cgroup v1 writes "no limit" as the largest page-aligned int64, not as a word.
|
|
18
|
+
const V1_UNLIMITED = 2 ** 60;
|
|
19
|
+
// mountinfo escapes spaces and other octal characters in paths as \NNN.
|
|
20
|
+
const unescape = (s) => s.replace(/\\([0-7]{3})/g, (_, n) => String.fromCharCode(parseInt(n, 8)));
|
|
21
|
+
function parseMountInfo(text) {
|
|
22
|
+
const mounts = [];
|
|
23
|
+
for (const line of text.split('\n')) {
|
|
24
|
+
const sep = line.indexOf(' - ');
|
|
25
|
+
if (sep < 0)
|
|
26
|
+
continue;
|
|
27
|
+
const pre = line.slice(0, sep).split(' ');
|
|
28
|
+
const post = line.slice(sep + 3).split(' ');
|
|
29
|
+
if (pre.length < 5 || post.length < 3)
|
|
30
|
+
continue;
|
|
31
|
+
mounts.push({ root: unescape(pre[3]), mountPoint: unescape(pre[4]), fsType: post[0], superOptions: post[2].split(',') });
|
|
32
|
+
}
|
|
33
|
+
return mounts;
|
|
34
|
+
}
|
|
35
|
+
// Maps a cgroup path, as /proc/self/cgroup gives it, to directories under the mount that shows it. A
|
|
36
|
+
// mount's root is the part of the hierarchy it exposes: "/" for a whole hierarchy or a private cgroup
|
|
37
|
+
// namespace, the container's own cgroup for Docker on cgroup v1.
|
|
38
|
+
function hierarchy(prefix, mount, path) {
|
|
39
|
+
let rel = path;
|
|
40
|
+
if (mount.root !== '/') {
|
|
41
|
+
rel = path === mount.root || path.startsWith(mount.root + '/') ? path.slice(mount.root.length) : '';
|
|
42
|
+
}
|
|
43
|
+
const base = prefix + mount.mountPoint;
|
|
44
|
+
const parts = rel.split('/').filter(Boolean);
|
|
45
|
+
const dirs = [];
|
|
46
|
+
for (let i = parts.length; i >= 0; i--) {
|
|
47
|
+
dirs.push([base, ...parts.slice(0, i)].join('/'));
|
|
48
|
+
}
|
|
49
|
+
return { dirs };
|
|
50
|
+
}
|
|
51
|
+
// Finds the cgroup this process is charged to. `prefix` is prepended to every path read, for tests.
|
|
52
|
+
export async function findCgroup(prefix = '') {
|
|
53
|
+
let self;
|
|
54
|
+
try {
|
|
55
|
+
self = await readFile(prefix + '/proc/self/cgroup', 'utf8');
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
const entries = self.split('\n').filter(Boolean).map(line => {
|
|
61
|
+
const [id, controllers, ...path] = line.split(':');
|
|
62
|
+
return { id, controllers: controllers ? controllers.split(',') : [], path: path.join(':') };
|
|
63
|
+
});
|
|
64
|
+
// A sandbox can refuse mountinfo while allowing the rest (AppArmor under snap does). Then assume
|
|
65
|
+
// the usual layout, each hierarchy mounted whole under /sys/fs/cgroup: walking up from the path
|
|
66
|
+
// still reaches the mount's root, which is the container's own cgroup under a private namespace
|
|
67
|
+
// and under Docker's v1 mounts alike.
|
|
68
|
+
let mounts;
|
|
69
|
+
try {
|
|
70
|
+
mounts = parseMountInfo(await readFile(prefix + '/proc/self/mountinfo', 'utf8'));
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
mounts = entries.map(e => e.controllers.length
|
|
74
|
+
? { root: '/', mountPoint: '/sys/fs/cgroup/' + e.controllers.join(','), fsType: 'cgroup', superOptions: e.controllers }
|
|
75
|
+
: { root: '/', mountPoint: '/sys/fs/cgroup', fsType: 'cgroup2', superOptions: [] });
|
|
76
|
+
}
|
|
77
|
+
// A v1 hierarchy for a controller wins over a v2 one: on a hybrid host the unified hierarchy is
|
|
78
|
+
// mounted but the cpu and memory controllers stay on v1.
|
|
79
|
+
const v1 = (controller) => {
|
|
80
|
+
const entry = entries.find(e => e.controllers.includes(controller));
|
|
81
|
+
const mount = mounts.find(m => m.fsType === 'cgroup' && m.superOptions.includes(controller));
|
|
82
|
+
return entry && mount ? hierarchy(prefix, mount, entry.path) : null;
|
|
83
|
+
};
|
|
84
|
+
const cpu = v1('cpu');
|
|
85
|
+
const memory = v1('memory');
|
|
86
|
+
if (cpu || memory) {
|
|
87
|
+
return { version: 1, cpu, memory };
|
|
88
|
+
}
|
|
89
|
+
const unified = entries.find(e => e.id === '0' && e.controllers.length === 0);
|
|
90
|
+
const mount = mounts.find(m => m.fsType === 'cgroup2');
|
|
91
|
+
if (unified && mount) {
|
|
92
|
+
const h = hierarchy(prefix, mount, unified.path);
|
|
93
|
+
return { version: 2, cpu: h, memory: h };
|
|
94
|
+
}
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
async function read(path) {
|
|
98
|
+
try {
|
|
99
|
+
return (await readFile(path, 'utf8')).trim();
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
function statField(text, key) {
|
|
106
|
+
if (!text)
|
|
107
|
+
return null;
|
|
108
|
+
const m = new RegExp(`^${key} (\\d+)$`, 'm').exec(text);
|
|
109
|
+
return m ? Number(m[1]) : null;
|
|
110
|
+
}
|
|
111
|
+
// The tightest CPU quota in cores on this cgroup or a parent, and where it is set.
|
|
112
|
+
async function cpuQuota(cg) {
|
|
113
|
+
if (!cg.cpu)
|
|
114
|
+
return null;
|
|
115
|
+
let best = null;
|
|
116
|
+
for (const dir of cg.cpu.dirs) {
|
|
117
|
+
let cores = null;
|
|
118
|
+
if (cg.version === 2) {
|
|
119
|
+
const [quota, period] = (await read(dir + '/cpu.max'))?.split(' ') ?? [];
|
|
120
|
+
if (quota && quota !== 'max' && Number(period) > 0)
|
|
121
|
+
cores = Number(quota) / Number(period);
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
const quota = Number(await read(dir + '/cpu.cfs_quota_us'));
|
|
125
|
+
const period = Number(await read(dir + '/cpu.cfs_period_us'));
|
|
126
|
+
if (quota > 0 && period > 0)
|
|
127
|
+
cores = quota / period;
|
|
128
|
+
}
|
|
129
|
+
if (cores !== null && cores > 0 && (!best || cores < best.value))
|
|
130
|
+
best = { value: cores, dir };
|
|
131
|
+
}
|
|
132
|
+
return best;
|
|
133
|
+
}
|
|
134
|
+
// The tightest memory limit in bytes on this cgroup or a parent, and where it is set.
|
|
135
|
+
async function memoryLimit(cg) {
|
|
136
|
+
if (!cg.memory)
|
|
137
|
+
return null;
|
|
138
|
+
let best = null;
|
|
139
|
+
for (const dir of cg.memory.dirs) {
|
|
140
|
+
const text = await read(dir + (cg.version === 2 ? '/memory.max' : '/memory.limit_in_bytes'));
|
|
141
|
+
if (!text || text === 'max')
|
|
142
|
+
continue;
|
|
143
|
+
const bytes = Number(text);
|
|
144
|
+
if (!(bytes > 0) || bytes >= V1_UNLIMITED)
|
|
145
|
+
continue;
|
|
146
|
+
if (!best || bytes < best.value)
|
|
147
|
+
best = { value: bytes, dir };
|
|
148
|
+
}
|
|
149
|
+
return best;
|
|
150
|
+
}
|
|
151
|
+
// Memory in use by the cgroup less its inactive file cache: the working set that container runtimes
|
|
152
|
+
// and the kubelet compare against the limit, since inactive cache is reclaimed before anything is killed.
|
|
153
|
+
async function workingSet(cg, dir) {
|
|
154
|
+
const usage = Number(await read(dir + (cg.version === 2 ? '/memory.current' : '/memory.usage_in_bytes')) ?? NaN);
|
|
155
|
+
if (!(usage >= 0))
|
|
156
|
+
return null;
|
|
157
|
+
const inactive = statField(await read(dir + '/memory.stat'), cg.version === 2 ? 'inactive_file' : 'total_inactive_file') ?? 0;
|
|
158
|
+
return Math.max(0, usage - inactive);
|
|
159
|
+
}
|
|
160
|
+
// Counts the CPUs this process may be scheduled on, from a list such as "0-3,8,10-11".
|
|
161
|
+
export function countCpuList(list) {
|
|
162
|
+
let n = 0;
|
|
163
|
+
for (const part of list.split(',')) {
|
|
164
|
+
const m = /^(\d+)(?:-(\d+))?$/.exec(part.trim());
|
|
165
|
+
if (!m)
|
|
166
|
+
return null;
|
|
167
|
+
n += m[2] === undefined ? 1 : Number(m[2]) - Number(m[1]) + 1;
|
|
168
|
+
}
|
|
169
|
+
return n > 0 ? n : null;
|
|
170
|
+
}
|
|
171
|
+
async function allowedCpus(prefix) {
|
|
172
|
+
const status = await read(prefix + '/proc/self/status');
|
|
173
|
+
const list = status && /^Cpus_allowed_list:\s*(\S+)$/m.exec(status)?.[1];
|
|
174
|
+
const n = list ? countCpuList(list) : null;
|
|
175
|
+
return n ?? os.availableParallelism();
|
|
176
|
+
}
|
|
177
|
+
const round = (n, places) => Math.round(n * 10 ** places) / 10 ** places;
|
|
178
|
+
class Nurse {
|
|
179
|
+
#prefix;
|
|
180
|
+
#cgroup = null;
|
|
181
|
+
#loop = null;
|
|
182
|
+
#elu = null;
|
|
183
|
+
#cpu = null;
|
|
184
|
+
#at = null;
|
|
185
|
+
#throttle = null;
|
|
186
|
+
constructor(prefix = '') {
|
|
187
|
+
this.#prefix = prefix;
|
|
188
|
+
}
|
|
189
|
+
start() {
|
|
190
|
+
this.#cgroup = findCgroup(this.#prefix).catch(() => null);
|
|
191
|
+
try {
|
|
192
|
+
this.#loop = monitorEventLoopDelay({ resolution: LOOP_RESOLUTION_MS });
|
|
193
|
+
this.#loop.enable();
|
|
194
|
+
}
|
|
195
|
+
catch {
|
|
196
|
+
this.#loop = null;
|
|
197
|
+
}
|
|
198
|
+
this.#cpu = null;
|
|
199
|
+
this.#at = null;
|
|
200
|
+
this.#elu = null;
|
|
201
|
+
this.#throttle = null;
|
|
202
|
+
}
|
|
203
|
+
stop() {
|
|
204
|
+
this.#loop?.disable();
|
|
205
|
+
this.#loop = null;
|
|
206
|
+
}
|
|
207
|
+
// Rates cover the time since the previous check. The first check after start() only sets the
|
|
208
|
+
// baseline, since at registration it would cover a few microseconds, so its rates are null.
|
|
209
|
+
async check() {
|
|
210
|
+
const first = this.#at === null;
|
|
211
|
+
const now = process.hrtime.bigint();
|
|
212
|
+
const cpuNow = process.cpuUsage();
|
|
213
|
+
const elapsedMicros = first ? 0 : Number(now - this.#at) / 1000;
|
|
214
|
+
const cpu = !first && this.#cpu && elapsedMicros > 0
|
|
215
|
+
? ((cpuNow.user - this.#cpu.user) + (cpuNow.system - this.#cpu.system)) / elapsedMicros
|
|
216
|
+
: null;
|
|
217
|
+
this.#cpu = cpuNow;
|
|
218
|
+
this.#at = now;
|
|
219
|
+
let loopDelay = null;
|
|
220
|
+
let loopDelayMax = null;
|
|
221
|
+
if (this.#loop) {
|
|
222
|
+
if (!first && this.#loop.count > 0) {
|
|
223
|
+
loopDelay = Math.max(0, this.#loop.percentile(99) / 1e6 - LOOP_RESOLUTION_MS);
|
|
224
|
+
loopDelayMax = Math.max(0, this.#loop.max / 1e6 - LOOP_RESOLUTION_MS);
|
|
225
|
+
}
|
|
226
|
+
this.#loop.reset();
|
|
227
|
+
}
|
|
228
|
+
let loopUtilization = null;
|
|
229
|
+
try {
|
|
230
|
+
const next = performance.eventLoopUtilization();
|
|
231
|
+
// Bun's is a stub that always reads zero, which would chart as an idle loop.
|
|
232
|
+
if (next.idle === 0 && next.active === 0)
|
|
233
|
+
throw new Error('unsupported');
|
|
234
|
+
if (!first && this.#elu)
|
|
235
|
+
loopUtilization = performance.eventLoopUtilization(next, this.#elu).utilization;
|
|
236
|
+
this.#elu = next;
|
|
237
|
+
}
|
|
238
|
+
catch { }
|
|
239
|
+
let heapUsed = null;
|
|
240
|
+
let heapLimit = null;
|
|
241
|
+
try {
|
|
242
|
+
const heap = v8.getHeapStatistics();
|
|
243
|
+
heapUsed = heap.used_heap_size;
|
|
244
|
+
heapLimit = heap.heap_size_limit;
|
|
245
|
+
}
|
|
246
|
+
catch { }
|
|
247
|
+
let rss = null;
|
|
248
|
+
try {
|
|
249
|
+
rss = process.memoryUsage.rss();
|
|
250
|
+
}
|
|
251
|
+
catch { }
|
|
252
|
+
const cg = await this.#cgroup;
|
|
253
|
+
const quota = cg ? await cpuQuota(cg) : null;
|
|
254
|
+
const memLimit = cg ? await memoryLimit(cg) : null;
|
|
255
|
+
const cpus = await allowedCpus(this.#prefix);
|
|
256
|
+
return {
|
|
257
|
+
cgroup: cg?.version ?? null,
|
|
258
|
+
cpu: cpu === null ? null : round(cpu, 3),
|
|
259
|
+
cpuLimit: round(quota ? Math.min(quota.value, cpus) : cpus, 3),
|
|
260
|
+
cpuThrottled: cg && quota ? await this.#throttled(cg, quota.dir) : null,
|
|
261
|
+
rss,
|
|
262
|
+
heapUsed,
|
|
263
|
+
heapLimit,
|
|
264
|
+
memoryUsed: cg && memLimit ? await workingSet(cg, memLimit.dir) : null,
|
|
265
|
+
memoryLimit: memLimit ? memLimit.value : os.totalmem(),
|
|
266
|
+
loopDelay: loopDelay === null ? null : round(loopDelay, 1),
|
|
267
|
+
loopDelayMax: loopDelayMax === null ? null : round(loopDelayMax, 1),
|
|
268
|
+
loopUtilization: loopUtilization === null ? null : round(loopUtilization, 3)
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
// The share of CPU periods since the previous check in which the cgroup that holds the quota ran
|
|
272
|
+
// out of it and was paused. Null on the first check, or when the quota moved to another cgroup.
|
|
273
|
+
async #throttled(cg, dir) {
|
|
274
|
+
const text = await read(dir + '/cpu.stat');
|
|
275
|
+
const periods = statField(text, 'nr_periods');
|
|
276
|
+
const throttled = statField(text, 'nr_throttled');
|
|
277
|
+
if (periods === null || throttled === null)
|
|
278
|
+
return null;
|
|
279
|
+
const prev = this.#throttle;
|
|
280
|
+
this.#throttle = { dir, periods, throttled };
|
|
281
|
+
if (!prev || prev.dir !== dir)
|
|
282
|
+
return null;
|
|
283
|
+
const dp = periods - prev.periods;
|
|
284
|
+
return dp > 0 ? round((throttled - prev.throttled) / dp, 3) : 0;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
export default Nurse;
|
package/dist/plans.d.ts
CHANGED
|
@@ -6,6 +6,10 @@ export interface SqlQuery {
|
|
|
6
6
|
}
|
|
7
7
|
export declare const PG_ERROR: {
|
|
8
8
|
divisionByZero: string;
|
|
9
|
+
lockNotAvailable: string;
|
|
10
|
+
foreignKeyViolation: string;
|
|
11
|
+
undefinedTable: string;
|
|
12
|
+
checkViolation: string;
|
|
9
13
|
};
|
|
10
14
|
export declare const DEFAULT_SCHEMA = "pgboss";
|
|
11
15
|
export declare const MIGRATE_RACE_MESSAGE = "division by zero";
|
|
@@ -90,12 +94,26 @@ export declare function createClockFunction(schema: string, options?: {
|
|
|
90
94
|
export declare function createTableWarning(schema: string): string;
|
|
91
95
|
export declare function createIndexWarning(schema: string): string;
|
|
92
96
|
export declare function createTableJobDependency(schema: string): string;
|
|
97
|
+
export declare const INSTANCE_QUIET_BEATS = 3;
|
|
98
|
+
export declare const INSTANCE_RETENTION_DAYS = 7;
|
|
99
|
+
export declare const INSTANCE_DEAD_KEPT_PER_NAME = 20;
|
|
100
|
+
export declare const INSTANCE_DEAD_KEPT = 1000;
|
|
101
|
+
export declare function pruneInstanceLives(schema: string, keep: number): string;
|
|
102
|
+
export declare function trimDeadInstances(schema: string, keep: number): string;
|
|
103
|
+
export declare function countCrashRestarts(schema: string): string;
|
|
104
|
+
export declare function crashRecountAt(schema: string): string;
|
|
105
|
+
export declare function registerInstance(schema: string): string;
|
|
106
|
+
export declare function heartbeatInstance(schema: string): string;
|
|
107
|
+
export declare function stopInstance(schema: string): string;
|
|
108
|
+
export declare function deleteOldInstances(schema: string, days: number): string;
|
|
109
|
+
export declare function getInstances(schema: string): string;
|
|
93
110
|
export declare function createIndexJobDependencyParent(schema: string): string;
|
|
111
|
+
export declare function createTableInstance(schema: string): string;
|
|
94
112
|
export declare function jobTableFormatFunction(schema: string): string;
|
|
95
113
|
export declare function createQueue(schema: string, name: string, options: unknown, noAdvisoryLocks?: boolean): string;
|
|
96
114
|
export declare function notifyChannelSql(schema: string): string;
|
|
97
115
|
export declare function notifyQueue(schema: string, name: string): string;
|
|
98
|
-
export declare function deleteQueue(schema: string, name: string, noAdvisoryLocks?: boolean): string;
|
|
116
|
+
export declare function deleteQueue(schema: string, name: string, noAdvisoryLocks?: boolean, partitioned?: boolean): string;
|
|
99
117
|
export declare function trySetQueueMonitorTime(schema: string, queues: string[], seconds: number, skipLocked?: boolean): SqlQuery;
|
|
100
118
|
export declare function setMonitorBackoff(schema: string, elapsedSeconds: number): SqlQuery;
|
|
101
119
|
export declare function trySetQueueDeletionTime(schema: string, queues: string[], seconds: number, skipLocked?: boolean): SqlQuery;
|
|
@@ -105,6 +123,7 @@ export declare function trySetFlowTime(schema: string, seconds: number): string;
|
|
|
105
123
|
export declare function trySetReindexTime(schema: string, seconds: number): string;
|
|
106
124
|
export declare function queueClaimSkipLocked(backend: string | undefined, noSkipLocked?: boolean): boolean;
|
|
107
125
|
export declare function updateQueue(schema: string): string;
|
|
126
|
+
export declare function currentDatabase(): string;
|
|
108
127
|
export declare function getQueues(schema: string, names?: string[]): SqlQuery;
|
|
109
128
|
export declare function deleteJobsById(schema: string, table: string, fenced?: boolean): string;
|
|
110
129
|
export declare function deleteQueuedJobs(schema: string, table: string): string;
|
|
@@ -165,6 +184,7 @@ interface FetchJobOptions {
|
|
|
165
184
|
policy: string | undefined;
|
|
166
185
|
limit: number;
|
|
167
186
|
includeMetadata?: boolean;
|
|
187
|
+
includeTraceContext?: boolean;
|
|
168
188
|
priority?: boolean;
|
|
169
189
|
orderByCreatedOn?: boolean;
|
|
170
190
|
ignoreStartAfter?: boolean;
|
|
@@ -204,8 +224,9 @@ interface InsertJobsOptions {
|
|
|
204
224
|
returnId?: boolean;
|
|
205
225
|
notify?: boolean;
|
|
206
226
|
slots?: boolean;
|
|
227
|
+
upsertByKey?: boolean;
|
|
207
228
|
}
|
|
208
|
-
export declare function insertJobs(schema: string, { table, name, returnId, notify, slots }: InsertJobsOptions): string;
|
|
229
|
+
export declare function insertJobs(schema: string, { table, name, returnId, notify, slots, upsertByKey }: InsertJobsOptions): string;
|
|
209
230
|
export declare function insertFlowJobs(schema: string, { table, name }: {
|
|
210
231
|
table: string;
|
|
211
232
|
name: string;
|
|
@@ -244,6 +265,9 @@ export interface DeltaWindowOptions {
|
|
|
244
265
|
}
|
|
245
266
|
export declare function deltaResetMax(intervalSeconds: number): string;
|
|
246
267
|
export declare function trueUpQueueStats(schema: string, table: string, queues: string[], noAdvisoryLocks?: boolean, window?: DeltaWindowOptions): string;
|
|
268
|
+
export declare const LATENCY_BINS = 46;
|
|
269
|
+
export declare const LATENCY_SLOTS: number;
|
|
270
|
+
export declare const LATENCY_MIN_SECONDS = 0.01;
|
|
247
271
|
export declare function getQueueStats(schema: string, table: string, queues: string[], throughput?: boolean, window?: DeltaWindowOptions): SqlQuery;
|
|
248
272
|
export declare const READY_HISTORY_SIZE = 60;
|
|
249
273
|
export declare function cacheQueueStats(schema: string, table: string, queues: string[], noAdvisoryLocks?: boolean, throughput?: boolean, window?: DeltaWindowOptions): string;
|
|
@@ -287,6 +311,7 @@ interface QueuePartition {
|
|
|
287
311
|
table: string;
|
|
288
312
|
policy?: string | null;
|
|
289
313
|
}
|
|
314
|
+
export declare function uninstall(schema: string, partitioned?: boolean): string;
|
|
290
315
|
export declare const EXPECTED_JOB_STATES: readonly string[];
|
|
291
316
|
export declare function expectedManagedTables(schema: string, partitioned: boolean, partitions?: QueuePartition[]): string[];
|
|
292
317
|
export declare function expectedManagedColumns(schema: string, partitioned: boolean, partitions?: QueuePartition[]): ExpectedColumns[];
|