pg-boss 12.19.0 → 12.20.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 -43
- package/dist/adapters/index.d.ts +2 -0
- package/dist/adapters/index.d.ts.map +1 -1
- package/dist/adapters/index.js +1 -0
- package/dist/adapters/pglite.d.ts +11 -0
- package/dist/adapters/pglite.d.ts.map +1 -0
- package/dist/adapters/pglite.js +37 -0
- package/dist/attorney.d.ts.map +1 -1
- package/dist/attorney.js +54 -0
- package/dist/boss.d.ts.map +1 -1
- package/dist/boss.js +23 -8
- package/dist/contractor.js +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +46 -18
- package/dist/manager.d.ts +8 -1
- package/dist/manager.d.ts.map +1 -1
- package/dist/manager.js +221 -11
- package/dist/migrationStore.d.ts +3 -3
- package/dist/migrationStore.d.ts.map +1 -1
- package/dist/migrationStore.js +8 -8
- package/dist/plans.d.ts +41 -11
- package/dist/plans.d.ts.map +1 -1
- package/dist/plans.js +277 -66
- package/dist/types.d.ts +37 -9
- package/dist/types.d.ts.map +1 -1
- package/package.json +9 -1
package/dist/manager.js
CHANGED
|
@@ -10,6 +10,34 @@ import * as types from "./types.js";
|
|
|
10
10
|
import Worker from "./worker.js";
|
|
11
11
|
import { JobSpy } from "./spy.js";
|
|
12
12
|
const INTERNAL_QUEUES = Object.values(timekeeper.QUEUES).reduce((acc, i) => ({ ...acc, [i]: i }), {});
|
|
13
|
+
// CockroachDB returns integer columns (INT8) as strings; these aliased metadata
|
|
14
|
+
// fields must be coerced back to numbers when backend === 'cockroachdb'.
|
|
15
|
+
const NUMERIC_METADATA_FIELDS = [
|
|
16
|
+
'priority',
|
|
17
|
+
'retryLimit',
|
|
18
|
+
'retryCount',
|
|
19
|
+
'retryDelay',
|
|
20
|
+
'retryDelayMax',
|
|
21
|
+
'expireInSeconds',
|
|
22
|
+
'heartbeatSeconds',
|
|
23
|
+
'deleteAfterSeconds',
|
|
24
|
+
'pendingDependencies'
|
|
25
|
+
];
|
|
26
|
+
// Queue rows (plans.getQueues) return these integer columns as strings on CockroachDB too.
|
|
27
|
+
const NUMERIC_QUEUE_FIELDS = [
|
|
28
|
+
'retryLimit',
|
|
29
|
+
'retryDelay',
|
|
30
|
+
'retryDelayMax',
|
|
31
|
+
'expireInSeconds',
|
|
32
|
+
'retentionSeconds',
|
|
33
|
+
'deleteAfterSeconds',
|
|
34
|
+
'heartbeatSeconds',
|
|
35
|
+
'deferredCount',
|
|
36
|
+
'warningQueueSize',
|
|
37
|
+
'queuedCount',
|
|
38
|
+
'activeCount',
|
|
39
|
+
'totalCount'
|
|
40
|
+
];
|
|
13
41
|
const events = {
|
|
14
42
|
error: 'error',
|
|
15
43
|
wip: 'wip'
|
|
@@ -664,7 +692,7 @@ class Manager extends EventEmitter {
|
|
|
664
692
|
limit: options.batchSize || 1,
|
|
665
693
|
ignoreSingletons: singletonsActive
|
|
666
694
|
};
|
|
667
|
-
const query = plans.fetchNextJob(fetchOptions);
|
|
695
|
+
const query = plans.fetchNextJob(fetchOptions, this.config.noSkipLocked);
|
|
668
696
|
let result;
|
|
669
697
|
try {
|
|
670
698
|
result = await db.executeSql(query.text, query.values);
|
|
@@ -672,7 +700,19 @@ class Manager extends EventEmitter {
|
|
|
672
700
|
catch (err) {
|
|
673
701
|
// errors from fetchquery should only be unique constraint violations
|
|
674
702
|
}
|
|
675
|
-
|
|
703
|
+
const rows = result?.rows || [];
|
|
704
|
+
// CockroachDB returns integer columns as strings; normalize them. Even a minimal fetch
|
|
705
|
+
// (JOB_COLUMNS_MIN) returns numeric fields like expireInSeconds/heartbeatSeconds, so normalize
|
|
706
|
+
// regardless of includeMetadata. The columns are aliased to camelCase, so use those keys.
|
|
707
|
+
if (this.config.backend === 'cockroachdb') {
|
|
708
|
+
for (const row of rows) {
|
|
709
|
+
for (const field of NUMERIC_METADATA_FIELDS) {
|
|
710
|
+
if (row[field] !== undefined && row[field] !== null)
|
|
711
|
+
row[field] = Number(row[field]);
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
return rows;
|
|
676
716
|
}
|
|
677
717
|
mapCompletionIdArg(id, funcName) {
|
|
678
718
|
const errorMessage = `${funcName}() requires an id`;
|
|
@@ -702,19 +742,164 @@ class Manager extends EventEmitter {
|
|
|
702
742
|
const db = this.assertDb(options);
|
|
703
743
|
const ids = this.mapCompletionIdArg(id, 'complete');
|
|
704
744
|
const { table } = await this.getQueueCache(name);
|
|
745
|
+
const outputData = this.mapCompletionDataArg(data);
|
|
746
|
+
// noMultiMutationCte: split the dependency-unblocking into a separate statement to
|
|
747
|
+
// avoid CockroachDB's multi-mutation CTE limitation (completeJobs updates two tables).
|
|
748
|
+
if (this.config.noMultiMutationCte) {
|
|
749
|
+
return this.completeDistributed(name, ids, outputData, table, db, options.includeQueued);
|
|
750
|
+
}
|
|
705
751
|
const sql = plans.completeJobs(this.config.schema, table, options.includeQueued);
|
|
706
|
-
const result = await db.executeSql(sql, [name, ids,
|
|
752
|
+
const result = await db.executeSql(sql, [name, ids, outputData]);
|
|
707
753
|
return this.mapCommandResponse(ids, result);
|
|
708
754
|
}
|
|
755
|
+
// Distributed complete/fail need several statements run atomically. When we own the pooled
|
|
756
|
+
// connection we pin a single client via withTransaction(); when the caller supplied their own
|
|
757
|
+
// db (options.db) we run the statements inline so they compose inside the caller's transaction
|
|
758
|
+
// rather than issuing a BEGIN/COMMIT that would commit or roll back their outer work.
|
|
759
|
+
async withDistributedTransaction(db, fn) {
|
|
760
|
+
if (db === this.db && this.db._pgbdb) {
|
|
761
|
+
return this.db.withTransaction(fn);
|
|
762
|
+
}
|
|
763
|
+
return fn(db);
|
|
764
|
+
}
|
|
765
|
+
async completeDistributed(name, ids, outputData, table, db, includeQueued) {
|
|
766
|
+
return this.withDistributedTransaction(db, async (tx) => {
|
|
767
|
+
// Step 1: Mark jobs completed and learn which ones were blocking dependents
|
|
768
|
+
const completeSql = plans.completeJobsDistributed(this.config.schema, table, includeQueued);
|
|
769
|
+
const { rows } = await tx.executeSql(completeSql, [name, ids, outputData]);
|
|
770
|
+
// Step 2: Decrement pending_dependencies for children of completed blocking parents
|
|
771
|
+
const blockingIds = rows.filter(row => row.blocking).map(row => row.id);
|
|
772
|
+
if (blockingIds.length > 0) {
|
|
773
|
+
const decrementSql = plans.decrementDependents(this.config.schema);
|
|
774
|
+
await tx.executeSql(decrementSql, [name, blockingIds]);
|
|
775
|
+
}
|
|
776
|
+
return { jobs: ids, requested: ids.length, affected: rows.length };
|
|
777
|
+
});
|
|
778
|
+
}
|
|
709
779
|
async fail(name, id, data, options = {}) {
|
|
710
780
|
Attorney.assertQueueName(name);
|
|
711
781
|
const db = this.assertDb(options);
|
|
712
782
|
const ids = this.mapCompletionIdArg(id, 'fail');
|
|
713
783
|
const { table } = await this.getQueueCache(name);
|
|
784
|
+
const outputData = this.mapCompletionDataArg(data);
|
|
785
|
+
// noMultiMutationCte: use separate queries to avoid CockroachDB's multi-mutation CTE limitation.
|
|
786
|
+
// The delete and re-insert run in a single transaction (see withDistributedTransaction) so the
|
|
787
|
+
// job cannot be lost between the two statements.
|
|
788
|
+
if (this.config.noMultiMutationCte) {
|
|
789
|
+
return this.failDistributed(name, ids, outputData, table, db);
|
|
790
|
+
}
|
|
714
791
|
const sql = plans.failJobsById(this.config.schema, table);
|
|
715
|
-
const result = await db.executeSql(sql, [name, ids,
|
|
792
|
+
const result = await db.executeSql(sql, [name, ids, outputData]);
|
|
716
793
|
return this.mapCommandResponse(ids, result);
|
|
717
794
|
}
|
|
795
|
+
async failDistributed(name, ids, outputData, table, db) {
|
|
796
|
+
// CockroachDB doesn't support multi-mutation CTEs, but does support transactions, so the
|
|
797
|
+
// delete + re-insert is split into separate statements run atomically.
|
|
798
|
+
return this.withDistributedTransaction(db, async (tx) => {
|
|
799
|
+
// Step 1: Select jobs to fail
|
|
800
|
+
const selectQuery = plans.selectJobsToFailById(this.config.schema, table);
|
|
801
|
+
const { rows: jobs } = await tx.executeSql(selectQuery.text, [name, ids]);
|
|
802
|
+
if (jobs.length === 0) {
|
|
803
|
+
return { jobs: ids, requested: ids.length, affected: 0 };
|
|
804
|
+
}
|
|
805
|
+
// Step 2: Delete the jobs
|
|
806
|
+
const deleteQuery = plans.deleteJobsToFail(this.config.schema, table);
|
|
807
|
+
await tx.executeSql(deleteQuery.text, [name, ids]);
|
|
808
|
+
// Step 3: Re-insert jobs with updated state
|
|
809
|
+
const count = await this.reinsertFailedJobs(tx, table, jobs, outputData);
|
|
810
|
+
return { jobs: ids, requested: ids.length, affected: count };
|
|
811
|
+
});
|
|
812
|
+
}
|
|
813
|
+
// Distributed equivalents of the supervisor's failJobsByTimeout/failJobsByHeartbeat maintenance.
|
|
814
|
+
// Those use the multi-mutation failJobs() CTE, which CockroachDB rejects, so on a distributed
|
|
815
|
+
// database we select the expired/timed-out jobs, delete them, and re-insert as retry/failed in a
|
|
816
|
+
// single transaction (the same split as failDistributed). Always run on the pooled connection.
|
|
817
|
+
async failJobsByTimeoutDistributed(table, queues) {
|
|
818
|
+
const select = plans.selectJobsToFailByTimeout(this.config.schema, table, queues);
|
|
819
|
+
return this.expireJobsDistributed(table, select, { value: { message: 'job timed out' } });
|
|
820
|
+
}
|
|
821
|
+
async failJobsByHeartbeatDistributed(table, queues) {
|
|
822
|
+
const select = plans.selectJobsToFailByHeartbeat(this.config.schema, table, queues);
|
|
823
|
+
return this.expireJobsDistributed(table, select, { value: { message: 'job heartbeat timeout' } });
|
|
824
|
+
}
|
|
825
|
+
async expireJobsDistributed(table, select, outputData) {
|
|
826
|
+
return this.withDistributedTransaction(this.db, async (tx) => {
|
|
827
|
+
const { rows: jobs } = await tx.executeSql(select.text, []);
|
|
828
|
+
if (jobs.length === 0) {
|
|
829
|
+
return 0;
|
|
830
|
+
}
|
|
831
|
+
const ids = jobs.map(job => job.id);
|
|
832
|
+
const deleteSql = plans.deleteJobsByIds(this.config.schema, table);
|
|
833
|
+
await tx.executeSql(deleteSql.text, [ids]);
|
|
834
|
+
return this.reinsertFailedJobs(tx, table, jobs, outputData);
|
|
835
|
+
});
|
|
836
|
+
}
|
|
837
|
+
// Re-insert a set of just-deleted jobs as retry (when retries remain) or failed (+ dead letter),
|
|
838
|
+
// preserving the flow/heartbeat columns. Shared by failDistributed and the distributed
|
|
839
|
+
// maintenance expiry above. Returns the number of jobs processed.
|
|
840
|
+
async reinsertFailedJobs(tx, table, jobs, outputData) {
|
|
841
|
+
const insertSql = plans.insertRetryJob(this.config.schema, table);
|
|
842
|
+
const dlqSql = plans.insertDeadLetterJob(this.config.schema);
|
|
843
|
+
let count = 0;
|
|
844
|
+
for (const job of jobs) {
|
|
845
|
+
// CockroachDB returns INT8 columns as strings. These rows come straight from a SELECT *, so
|
|
846
|
+
// unlike fetch/getJobById they are never normalized. Coerce the fields used in arithmetic and
|
|
847
|
+
// comparison below — otherwise `retry_count < retry_limit` is a lexicographic string compare
|
|
848
|
+
// ("9" < "10" === false, wrongly failing a retriable job) and `retry_count + 1` concatenates.
|
|
849
|
+
const retryCount = Number(job.retry_count);
|
|
850
|
+
const retryLimit = Number(job.retry_limit);
|
|
851
|
+
const retryDelay = Number(job.retry_delay);
|
|
852
|
+
const retryDelayMax = job.retry_delay_max != null ? Number(job.retry_delay_max) : null;
|
|
853
|
+
const canRetry = retryCount < retryLimit;
|
|
854
|
+
let retried = false;
|
|
855
|
+
if (canRetry) {
|
|
856
|
+
// Calculate start_after for retry
|
|
857
|
+
let startAfter = job.start_after;
|
|
858
|
+
if (!job.retry_backoff) {
|
|
859
|
+
startAfter = new Date(Date.now() + retryDelay * 1000);
|
|
860
|
+
}
|
|
861
|
+
else {
|
|
862
|
+
const exp = Math.min(16, retryCount + 1);
|
|
863
|
+
const delay = retryDelay * (Math.pow(2, exp) / 2 + Math.pow(2, exp) / 2 * Math.random());
|
|
864
|
+
// Match the canonical failJobs() SQL: LEAST(retry_delay_max, delay) caps the backoff,
|
|
865
|
+
// treating NULL as "no cap" and 0 as a real cap. (`?:` would wrongly treat 0 as no cap.)
|
|
866
|
+
const cappedDelay = retryDelayMax != null ? Math.min(retryDelayMax, delay) : delay;
|
|
867
|
+
startAfter = new Date(Date.now() + cappedDelay * 1000);
|
|
868
|
+
}
|
|
869
|
+
// heartbeat_on resets to NULL on re-insert; heartbeat_seconds/blocked/blocking/
|
|
870
|
+
// pending_dependencies are preserved so flows and heartbeat detection survive a retry
|
|
871
|
+
// (matches the non-distributed failJobs() CTE).
|
|
872
|
+
const { rows } = await tx.executeSql(insertSql, [
|
|
873
|
+
job.id, job.name, job.priority, job.data, 'retry', job.retry_limit, job.retry_count,
|
|
874
|
+
job.retry_delay, job.retry_backoff, job.retry_delay_max, startAfter, job.started_on,
|
|
875
|
+
job.singleton_key, job.singleton_on, job.group_id, job.group_tier, job.expire_seconds,
|
|
876
|
+
job.deletion_seconds, job.created_on, null, job.keep_until, job.policy,
|
|
877
|
+
outputData, job.dead_letter,
|
|
878
|
+
null, job.heartbeat_seconds, job.blocked, job.blocking, job.pending_dependencies
|
|
879
|
+
]);
|
|
880
|
+
// The retry insert can be dropped by ON CONFLICT when the queue policy (e.g. stately,
|
|
881
|
+
// singleton, key_strict_fifo) already has a non-terminal job. Mirror the failed_jobs
|
|
882
|
+
// fallback of the non-distributed failJobs() CTE in that case.
|
|
883
|
+
retried = rows.length > 0;
|
|
884
|
+
}
|
|
885
|
+
if (!retried) {
|
|
886
|
+
await tx.executeSql(insertSql, [
|
|
887
|
+
job.id, job.name, job.priority, job.data, 'failed', job.retry_limit, job.retry_count,
|
|
888
|
+
job.retry_delay, job.retry_backoff, job.retry_delay_max, job.start_after, job.started_on,
|
|
889
|
+
job.singleton_key, job.singleton_on, job.group_id, job.group_tier, job.expire_seconds,
|
|
890
|
+
job.deletion_seconds, job.created_on, new Date(), job.keep_until, job.policy,
|
|
891
|
+
outputData, job.dead_letter,
|
|
892
|
+
null, job.heartbeat_seconds, job.blocked, job.blocking, job.pending_dependencies
|
|
893
|
+
]);
|
|
894
|
+
// Insert to dead letter queue if failed and has dead_letter configured
|
|
895
|
+
if (job.dead_letter) {
|
|
896
|
+
await tx.executeSql(dlqSql, [job.dead_letter, job.data, outputData]);
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
count++;
|
|
900
|
+
}
|
|
901
|
+
return count;
|
|
902
|
+
}
|
|
718
903
|
async deleteJob(name, id, options = {}) {
|
|
719
904
|
Attorney.assertQueueName(name);
|
|
720
905
|
const db = this.assertDb(options);
|
|
@@ -779,7 +964,7 @@ class Manager extends EventEmitter {
|
|
|
779
964
|
notStrictEqual(name, options.deadLetter, 'deadLetter cannot be itself');
|
|
780
965
|
await this.getQueueCache(options.deadLetter);
|
|
781
966
|
}
|
|
782
|
-
const sql = plans.createQueue(this.config.schema, name, { ...options, policy });
|
|
967
|
+
const sql = plans.createQueue(this.config.schema, name, { ...options, policy }, this.config.noAdvisoryLocks);
|
|
783
968
|
await this.db.executeSql(sql);
|
|
784
969
|
}
|
|
785
970
|
async getBlockedKeys(name) {
|
|
@@ -801,6 +986,15 @@ class Manager extends EventEmitter {
|
|
|
801
986
|
}
|
|
802
987
|
const query = plans.getQueues(this.config.schema, names);
|
|
803
988
|
const { rows } = await this.db.executeSql(query.text, query.values);
|
|
989
|
+
// CockroachDB returns integer columns as strings; normalize the numeric queue fields.
|
|
990
|
+
if (this.config.backend === 'cockroachdb') {
|
|
991
|
+
for (const row of rows) {
|
|
992
|
+
for (const field of NUMERIC_QUEUE_FIELDS) {
|
|
993
|
+
if (row[field] !== undefined && row[field] !== null)
|
|
994
|
+
row[field] = Number(row[field]);
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
}
|
|
804
998
|
return rows;
|
|
805
999
|
}
|
|
806
1000
|
async updateQueue(name, options = {}) {
|
|
@@ -822,16 +1016,14 @@ class Manager extends EventEmitter {
|
|
|
822
1016
|
await this.db.executeSql(sql, [name, options]);
|
|
823
1017
|
}
|
|
824
1018
|
async getQueue(name) {
|
|
825
|
-
|
|
826
|
-
const query = plans.getQueues(this.config.schema, [name]);
|
|
827
|
-
const { rows } = await this.db.executeSql(query.text, query.values);
|
|
1019
|
+
const rows = await this.getQueues([name]);
|
|
828
1020
|
return rows[0] || null;
|
|
829
1021
|
}
|
|
830
1022
|
async deleteQueue(name) {
|
|
831
1023
|
Attorney.assertQueueName(name);
|
|
832
1024
|
try {
|
|
833
1025
|
await this.getQueueCache(name);
|
|
834
|
-
const sql = plans.deleteQueue(this.config.schema, name);
|
|
1026
|
+
const sql = plans.deleteQueue(this.config.schema, name, this.config.noAdvisoryLocks);
|
|
835
1027
|
await this.db.executeSql(sql);
|
|
836
1028
|
}
|
|
837
1029
|
catch { }
|
|
@@ -870,7 +1062,16 @@ class Manager extends EventEmitter {
|
|
|
870
1062
|
const queue = await this.getQueueCache(name);
|
|
871
1063
|
const query = plans.getQueueStats(this.config.schema, queue.table, [name]);
|
|
872
1064
|
const { rows } = await this.db.executeSql(query.text, query.values);
|
|
873
|
-
|
|
1065
|
+
const stats = rows.at(0);
|
|
1066
|
+
// CockroachDB returns integer columns as strings; normalize the stats counts. (The queue fields
|
|
1067
|
+
// merged in below come from getQueueCache -> getQueues, which already normalizes them.)
|
|
1068
|
+
if (stats && this.config.backend === 'cockroachdb') {
|
|
1069
|
+
for (const field of NUMERIC_QUEUE_FIELDS) {
|
|
1070
|
+
if (stats[field] !== undefined && stats[field] !== null)
|
|
1071
|
+
stats[field] = Number(stats[field]);
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
return Object.assign(queue, stats ||
|
|
874
1075
|
{
|
|
875
1076
|
deferredCount: 0,
|
|
876
1077
|
queuedCount: 0,
|
|
@@ -885,7 +1086,16 @@ class Manager extends EventEmitter {
|
|
|
885
1086
|
const sql = plans.getJobById(this.config.schema, table);
|
|
886
1087
|
const result1 = await db.executeSql(sql, [name, id]);
|
|
887
1088
|
if (result1?.rows?.length === 1) {
|
|
888
|
-
|
|
1089
|
+
const row = result1.rows[0];
|
|
1090
|
+
// CockroachDB returns integer columns as strings; normalize the numeric
|
|
1091
|
+
// metadata fields so callers get numbers regardless of the backend.
|
|
1092
|
+
if (this.config.backend === 'cockroachdb') {
|
|
1093
|
+
for (const field of NUMERIC_METADATA_FIELDS) {
|
|
1094
|
+
if (row[field] !== undefined && row[field] !== null)
|
|
1095
|
+
row[field] = Number(row[field]);
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
return row;
|
|
889
1099
|
}
|
|
890
1100
|
else {
|
|
891
1101
|
return null;
|
package/dist/migrationStore.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as types from './types.ts';
|
|
2
|
-
declare function rollback(schema: string, version: number, migrations?: types.Migration[]): string;
|
|
3
|
-
declare function next(schema: string, version: number, migrations: types.Migration[] | undefined): string;
|
|
4
|
-
declare function migrate(schema: string, version: number, migrations?: types.Migration[]): string;
|
|
2
|
+
declare function rollback(schema: string, version: number, migrations?: types.Migration[], noAdvisoryLocks?: boolean): string;
|
|
3
|
+
declare function next(schema: string, version: number, migrations: types.Migration[] | undefined, noAdvisoryLocks?: boolean): string;
|
|
4
|
+
declare function migrate(schema: string, version: number, migrations?: types.Migration[], noAdvisoryLocks?: boolean): string;
|
|
5
5
|
declare function getAll(schema: string): types.Migration[];
|
|
6
6
|
export { rollback, next, migrate, getAll, };
|
|
7
7
|
//# sourceMappingURL=migrationStore.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migrationStore.d.ts","sourceRoot":"","sources":["../src/migrationStore.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AASnC,iBAAS,QAAQ,CAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,KAAK,CAAC,SAAS,EAAE,
|
|
1
|
+
{"version":3,"file":"migrationStore.d.ts","sourceRoot":"","sources":["../src/migrationStore.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AASnC,iBAAS,QAAQ,CAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,KAAK,CAAC,SAAS,EAAE,EAAE,eAAe,CAAC,EAAE,OAAO,UAQ5G;AAED,iBAAS,IAAI,CAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,CAAC,SAAS,EAAE,GAAG,SAAS,EAAE,eAAe,CAAC,EAAE,OAAO,UAQnH;AAED,iBAAS,OAAO,CAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,KAAK,CAAC,SAAS,EAAE,EAAE,eAAe,CAAC,EAAE,OAAO,UAuB3G;AAED,iBAAS,MAAM,CAAE,MAAM,EAAE,MAAM,GAAG,KAAK,CAAC,SAAS,EAAE,CAq8BlD;AAED,OAAO,EACL,QAAQ,EACR,IAAI,EACJ,OAAO,EACP,MAAM,GACP,CAAA"}
|
package/dist/migrationStore.js
CHANGED
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
import assert from 'node:assert';
|
|
2
2
|
import * as plans from "./plans.js";
|
|
3
3
|
import * as types from "./types.js";
|
|
4
|
-
function flatten(schema, commands, version) {
|
|
4
|
+
function flatten(schema, commands, version, noAdvisoryLocks) {
|
|
5
5
|
commands.unshift(plans.assertMigration(schema, version));
|
|
6
6
|
commands.push(plans.setVersion(schema, version));
|
|
7
|
-
return plans.locked(schema, commands);
|
|
7
|
+
return plans.locked(schema, commands, undefined, noAdvisoryLocks);
|
|
8
8
|
}
|
|
9
|
-
function rollback(schema, version, migrations) {
|
|
9
|
+
function rollback(schema, version, migrations, noAdvisoryLocks) {
|
|
10
10
|
migrations = migrations || getAll(schema);
|
|
11
11
|
const result = migrations.find(i => i.version === version);
|
|
12
12
|
assert(result, `Version ${version} not found.`);
|
|
13
|
-
return flatten(schema, result.uninstall || [], result.previous);
|
|
13
|
+
return flatten(schema, result.uninstall || [], result.previous, noAdvisoryLocks);
|
|
14
14
|
}
|
|
15
|
-
function next(schema, version, migrations) {
|
|
15
|
+
function next(schema, version, migrations, noAdvisoryLocks) {
|
|
16
16
|
migrations = migrations || getAll(schema);
|
|
17
17
|
const result = migrations.find(i => i.previous === version);
|
|
18
18
|
assert(result, `Version ${version} not found.`);
|
|
19
|
-
return flatten(schema, result.install, result.version);
|
|
19
|
+
return flatten(schema, result.install, result.version, noAdvisoryLocks);
|
|
20
20
|
}
|
|
21
|
-
function migrate(schema, version, migrations) {
|
|
21
|
+
function migrate(schema, version, migrations, noAdvisoryLocks) {
|
|
22
22
|
migrations = migrations || getAll(schema);
|
|
23
23
|
const result = migrations
|
|
24
24
|
.filter(i => i.previous >= version)
|
|
@@ -33,7 +33,7 @@ function migrate(schema, version, migrations) {
|
|
|
33
33
|
return acc;
|
|
34
34
|
}, { install: [], version });
|
|
35
35
|
assert(result.install.length > 0, `Version ${version} not found.`);
|
|
36
|
-
return flatten(schema, result.install, result.version);
|
|
36
|
+
return flatten(schema, result.install, result.version, noAdvisoryLocks);
|
|
37
37
|
}
|
|
38
38
|
function getAll(schema) {
|
|
39
39
|
return [
|
package/dist/plans.d.ts
CHANGED
|
@@ -25,15 +25,20 @@ export declare const QUEUE_POLICIES: Readonly<{
|
|
|
25
25
|
exclusive: "exclusive";
|
|
26
26
|
key_strict_fifo: "key_strict_fifo";
|
|
27
27
|
}>;
|
|
28
|
-
|
|
28
|
+
interface CreateOptions {
|
|
29
29
|
createSchema?: boolean;
|
|
30
|
-
|
|
30
|
+
noTablePartitioning?: boolean;
|
|
31
|
+
noDeferrableConstraints?: boolean;
|
|
32
|
+
noAdvisoryLocks?: boolean;
|
|
33
|
+
noCoveringIndexes?: boolean;
|
|
34
|
+
}
|
|
35
|
+
export declare function create(schema: string, version: number, options?: CreateOptions): string;
|
|
31
36
|
export declare function createTableWarning(schema: string): string;
|
|
32
37
|
export declare function createIndexWarning(schema: string): string;
|
|
33
38
|
export declare function createTableJobDependency(schema: string): string;
|
|
34
39
|
export declare function createIndexJobDependencyParent(schema: string): string;
|
|
35
|
-
export declare function createQueue(schema: string, name: string, options: unknown): string;
|
|
36
|
-
export declare function deleteQueue(schema: string, name: string): string;
|
|
40
|
+
export declare function createQueue(schema: string, name: string, options: unknown, noAdvisoryLocks?: boolean): string;
|
|
41
|
+
export declare function deleteQueue(schema: string, name: string, noAdvisoryLocks?: boolean): string;
|
|
37
42
|
export declare function trySetQueueMonitorTime(schema: string, queues: string[], seconds: number): SqlQuery;
|
|
38
43
|
export declare function trySetQueueDeletionTime(schema: string, queues: string[], seconds: number): SqlQuery;
|
|
39
44
|
export declare function trySetCronTime(schema: string, seconds: number): string;
|
|
@@ -81,7 +86,23 @@ interface FetchJobOptions {
|
|
|
81
86
|
minPriority?: number;
|
|
82
87
|
maxPriority?: number;
|
|
83
88
|
}
|
|
84
|
-
|
|
89
|
+
/**
|
|
90
|
+
* Builds the fetch query for claiming jobs from the queue.
|
|
91
|
+
*
|
|
92
|
+
* With SKIP LOCKED (noSkipLocked=false, the default), uses SELECT FOR UPDATE SKIP
|
|
93
|
+
* LOCKED, which lets multiple workers efficiently fetch different jobs simultaneously.
|
|
94
|
+
*
|
|
95
|
+
* With noSkipLocked=true, omits FOR UPDATE SKIP LOCKED and adds an additional state
|
|
96
|
+
* check in the WHERE clause. This pattern works better with distributed databases like
|
|
97
|
+
* CockroachDB where SKIP LOCKED has performance issues and can unexpectedly skip
|
|
98
|
+
* unlocked rows.
|
|
99
|
+
*
|
|
100
|
+
* Trade-off when noSkipLocked is set: under high contention, workers may receive fewer
|
|
101
|
+
* jobs per fetch as concurrent updates to the same rows will result in some workers
|
|
102
|
+
* getting empty results. This is acceptable for job queues where processing time
|
|
103
|
+
* exceeds fetch time.
|
|
104
|
+
*/
|
|
105
|
+
export declare function fetchNextJob(options: FetchJobOptions, noSkipLocked?: boolean): SqlQuery;
|
|
85
106
|
export declare function completeJobs(schema: string, table: string, includeQueued?: boolean): string;
|
|
86
107
|
export declare function cancelJobs(schema: string, table: string): string;
|
|
87
108
|
export declare function resumeJobs(schema: string, table: string): string;
|
|
@@ -93,17 +114,26 @@ interface InsertJobsOptions {
|
|
|
93
114
|
}
|
|
94
115
|
export declare function insertJobs(schema: string, { table, name, returnId }: InsertJobsOptions): string;
|
|
95
116
|
export declare function failJobsById(schema: string, table: string): string;
|
|
96
|
-
export declare function failJobsByTimeout(schema: string, table: string, queues: string[]): string;
|
|
97
|
-
export declare function failJobsByHeartbeat(schema: string, table: string, queues: string[]): string;
|
|
117
|
+
export declare function failJobsByTimeout(schema: string, table: string, queues: string[], noAdvisoryLocks?: boolean): string;
|
|
118
|
+
export declare function failJobsByHeartbeat(schema: string, table: string, queues: string[], noAdvisoryLocks?: boolean): string;
|
|
98
119
|
export declare function touchJobs(schema: string, table: string): string;
|
|
99
|
-
export declare function
|
|
120
|
+
export declare function selectJobsToFailById(schema: string, table: string): SqlQuery;
|
|
121
|
+
export declare function deleteJobsToFail(schema: string, table: string): SqlQuery;
|
|
122
|
+
export declare function selectJobsToFailByTimeout(schema: string, table: string, queues: string[]): SqlQuery;
|
|
123
|
+
export declare function selectJobsToFailByHeartbeat(schema: string, table: string, queues: string[]): SqlQuery;
|
|
124
|
+
export declare function deleteJobsByIds(schema: string, table: string): SqlQuery;
|
|
125
|
+
export declare function completeJobsDistributed(schema: string, table: string, includeQueued?: boolean): string;
|
|
126
|
+
export declare function decrementDependents(schema: string): string;
|
|
127
|
+
export declare function insertRetryJob(schema: string, table: string): string;
|
|
128
|
+
export declare function insertDeadLetterJob(schema: string): string;
|
|
129
|
+
export declare function deletion(schema: string, table: string, queues: string[], noAdvisoryLocks?: boolean): string;
|
|
100
130
|
export declare function retryJobs(schema: string, table: string): string;
|
|
101
131
|
export declare function getQueueStats(schema: string, table: string, queues: string[]): SqlQuery;
|
|
102
|
-
export declare function cacheQueueStats(schema: string, table: string, queues: string[]): string;
|
|
132
|
+
export declare function cacheQueueStats(schema: string, table: string, queues: string[], noAdvisoryLocks?: boolean): string;
|
|
103
133
|
export declare function serializeArrayParam(values: string[]): string;
|
|
104
134
|
export declare function serializeJsonParam(value: unknown): string;
|
|
105
135
|
export declare function transaction(query: string | string[]): string;
|
|
106
|
-
export declare function locked(schema: string, query: string | string[], key?: string): string;
|
|
136
|
+
export declare function locked(schema: string, query: string | string[], key?: string, noAdvisoryLocks?: boolean): string;
|
|
107
137
|
export declare function assertMigration(schema: string, version: number): string;
|
|
108
138
|
export declare function findJobs(schema: string, table: string, options: {
|
|
109
139
|
queued: boolean;
|
|
@@ -115,7 +145,7 @@ export declare function getJobById(schema: string, table: string): string;
|
|
|
115
145
|
export declare function insertDependencies(schema: string): string;
|
|
116
146
|
export declare function getDependencies(schema: string): string;
|
|
117
147
|
export declare function getDependents(schema: string): string;
|
|
118
|
-
export declare function cleanupDependencies(schema: string, table: string, queues: string[]): string;
|
|
148
|
+
export declare function cleanupDependencies(schema: string, table: string, queues: string[], noAdvisoryLocks?: boolean): string;
|
|
119
149
|
export declare function getBlockedKeys(schema: string, table: string): string;
|
|
120
150
|
export declare function getNextBamCommand(schema: string): string;
|
|
121
151
|
export declare function setBamCompleted(schema: string, id: string): string;
|
package/dist/plans.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plans.d.ts","sourceRoot":"","sources":["../src/plans.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA;AAEpD,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,OAAO,EAAE,CAAA;CAClB;AAED,eAAO,MAAM,QAAQ;;CAEpB,CAAA;AAED,eAAO,MAAM,cAAc,WAAW,CAAA;AACtC,eAAO,MAAM,oBAAoB,qBAAqB,CAAA;AACtD,eAAO,MAAM,mBAAmB,mBAAmB,CAAA;AAMnD,eAAO,MAAM,UAAU;;;;;;;EAOrB,CAAA;AAEF,eAAO,MAAM,cAAc;;;;;;;EAOzB,CAAA;AAeF,
|
|
1
|
+
{"version":3,"file":"plans.d.ts","sourceRoot":"","sources":["../src/plans.ts"],"names":[],"mappings":"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"}
|