@alexify/migronaut 2.0.0 → 2.2.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/CHANGELOG.md +436 -0
- package/README.md +235 -6
- package/bullmq.d.ts +860 -0
- package/bullmq.js +1 -0
- package/index.d.ts +888 -19
- package/migronaut.schema.json +238 -1
- package/package.json +21 -5
- package/src/bullmq/index.js +55 -0
- package/src/bullmq/jobs.js +454 -0
- package/src/bullmq/processor.js +632 -0
- package/src/bullmq/producer.js +427 -0
- package/src/bullmq/service.js +653 -0
- package/src/bullmq/wait.js +124 -0
- package/src/cli/args.js +12 -2
- package/src/cli/commands/converge.js +188 -0
- package/src/cli/commands/down.js +2 -0
- package/src/cli/commands/lock.js +2 -1
- package/src/cli/commands/redo.js +8 -1
- package/src/cli/commands/up.js +14 -1
- package/src/cli/exit-codes.js +9 -2
- package/src/cli/index.js +2 -0
- package/src/cli/shared.js +14 -4
- package/src/cli/table.js +164 -0
- package/src/core/audit.js +88 -3
- package/src/core/changelog.js +71 -6
- package/src/core/collections.js +396 -0
- package/src/core/config.js +130 -25
- package/src/core/converge-log.js +47 -0
- package/src/core/converge-plan.js +686 -0
- package/src/core/converge-search-run.js +440 -0
- package/src/core/converge-search.js +404 -0
- package/src/core/converge.js +1024 -0
- package/src/core/index-spec.js +507 -0
- package/src/core/lock-wait.js +260 -0
- package/src/core/lock.js +95 -28
- package/src/core/migrator.js +600 -287
- package/src/core/options.js +266 -0
- package/src/core/run-recorder.js +157 -0
- package/src/core/run.js +58 -90
- package/src/core/search-index-spec.js +758 -0
- package/src/core/sequence.js +134 -0
- package/src/core/server-info.js +63 -0
- package/src/errors/index.js +60 -0
- package/src/index.js +8 -0
- package/src/utils/actor.js +48 -0
- package/src/utils/canonical.js +212 -0
- package/src/utils/collection-name.js +21 -0
- package/src/utils/error.js +18 -1
- package/src/utils/id.js +77 -0
- package/src/utils/loader.js +39 -21
- package/src/utils/migration-name.js +32 -0
- package/src/utils/redact.js +21 -1
- package/src/utils/telemetry.js +410 -0
- package/src/utils/template.js +43 -2
package/bullmq.d.ts
ADDED
|
@@ -0,0 +1,860 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
AuditReport,
|
|
3
|
+
CollectionConvergeResult,
|
|
4
|
+
ConvergeSearchSummary,
|
|
5
|
+
ConvergeUnstable,
|
|
6
|
+
LockInfo,
|
|
7
|
+
MigratorKit,
|
|
8
|
+
MigratorKitOptions,
|
|
9
|
+
MigronautConfig,
|
|
10
|
+
MigronautErrorCode,
|
|
11
|
+
OnLockHeld,
|
|
12
|
+
StatusRow,
|
|
13
|
+
} from './index.js';
|
|
14
|
+
|
|
15
|
+
// ─── Structural BullMQ surface ─────────────────────────────────────────────────
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Structural stand-ins for BullMQ's `Job`, `Queue`, `Worker` and `QueueEvents`
|
|
19
|
+
* — only the members the adapter actually calls.
|
|
20
|
+
*
|
|
21
|
+
* Deliberately not `import type { Queue } from 'bullmq'`: bullmq is not a
|
|
22
|
+
* dependency of migronaut of any kind — you inject its classes — so a hard
|
|
23
|
+
* import would make this declaration file fail to resolve for everyone who has
|
|
24
|
+
* not installed it. The real classes are assignable to these (pinned by the
|
|
25
|
+
* type tests against the real package), and the factory is generic over what
|
|
26
|
+
* you inject, so `mq.queue` and `mq.worker` are your own `Queue`/`Worker`.
|
|
27
|
+
* Injected classes are inferred with BullMQ's widest type arguments; name the
|
|
28
|
+
* instance types to pin them — `createMigrationQueue<Queue, Worker>(…)`.
|
|
29
|
+
*
|
|
30
|
+
* Methods use shorthand syntax on purpose: method parameters are compared
|
|
31
|
+
* bivariantly, which is what lets BullMQ's generic, overloaded signatures
|
|
32
|
+
* satisfy these without being imported.
|
|
33
|
+
*/
|
|
34
|
+
export interface BullMQJobLike<Data = any, Result = any> {
|
|
35
|
+
id?: string;
|
|
36
|
+
name: string;
|
|
37
|
+
data: Data;
|
|
38
|
+
opts: { attempts?: number };
|
|
39
|
+
attemptsMade: number;
|
|
40
|
+
progress: unknown;
|
|
41
|
+
returnvalue: Result;
|
|
42
|
+
failedReason: string;
|
|
43
|
+
timestamp: number;
|
|
44
|
+
processedOn?: number;
|
|
45
|
+
finishedOn?: number;
|
|
46
|
+
updateProgress(progress: any): Promise<void>;
|
|
47
|
+
log(row: string): Promise<number>;
|
|
48
|
+
getState(): Promise<string>;
|
|
49
|
+
waitUntilFinished(queueEvents: any, ttl?: number): Promise<Result>;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** See {@link BullMQJobLike} for why this is structural */
|
|
53
|
+
export interface BullMQQueueLike {
|
|
54
|
+
name: string;
|
|
55
|
+
addBulk(jobs: (MigrationJobSpec | ConvergeJobSpec)[]): Promise<BullMQJobLike[]>;
|
|
56
|
+
getJob(id: string): Promise<BullMQJobLike | undefined>;
|
|
57
|
+
pause(): Promise<void>;
|
|
58
|
+
resume(): Promise<void>;
|
|
59
|
+
close(): Promise<void>;
|
|
60
|
+
/** BullMQ ≥ 5.9 — used when present to cap the queue at one active job */
|
|
61
|
+
setGlobalConcurrency?(concurrency: number): Promise<unknown>;
|
|
62
|
+
/** BullMQ ≥ 5.16 — needed by `schedule()` */
|
|
63
|
+
upsertJobScheduler?(id: string, repeat: any, template?: any): Promise<unknown>;
|
|
64
|
+
/** BullMQ ≥ 5.16 — needed by `unschedule()` */
|
|
65
|
+
removeJobScheduler?(id: string): Promise<boolean>;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** See {@link BullMQJobLike} for why this is structural */
|
|
69
|
+
export interface BullMQWorkerLike {
|
|
70
|
+
name: string;
|
|
71
|
+
close(force?: boolean): Promise<void>;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** See {@link BullMQJobLike} for why this is structural */
|
|
75
|
+
export interface BullMQQueueEventsLike {
|
|
76
|
+
/** Present on every QueueEvents — how an injected instance is told apart from the class */
|
|
77
|
+
on(event: string, listener: (...args: any[]) => void): unknown;
|
|
78
|
+
close(): Promise<void>;
|
|
79
|
+
waitUntilReady?(): Promise<unknown>;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** The `Queue` class: `new Queue(name, { connection, prefix })` */
|
|
83
|
+
export type BullMQQueueClass<Q extends BullMQQueueLike = BullMQQueueLike> = new (
|
|
84
|
+
name: string,
|
|
85
|
+
opts: any,
|
|
86
|
+
) => Q;
|
|
87
|
+
|
|
88
|
+
/** The `Worker` class: `new Worker(name, processor, { connection, concurrency, … })` */
|
|
89
|
+
export type BullMQWorkerClass<W extends BullMQWorkerLike = BullMQWorkerLike> = new (
|
|
90
|
+
name: string,
|
|
91
|
+
processor: any,
|
|
92
|
+
opts: any,
|
|
93
|
+
) => W;
|
|
94
|
+
|
|
95
|
+
/** The `QueueEvents` class: `new QueueEvents(name, { connection, prefix })` */
|
|
96
|
+
export type BullMQQueueEventsClass<E extends BullMQQueueEventsLike = BullMQQueueEventsLike> = new (
|
|
97
|
+
name: string,
|
|
98
|
+
opts: any,
|
|
99
|
+
) => E;
|
|
100
|
+
|
|
101
|
+
// ─── Job contract ──────────────────────────────────────────────────────────────
|
|
102
|
+
|
|
103
|
+
export type MigrationJobName = 'up' | 'down' | 'sync' | 'converge';
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Job names: `up`/`down` carry one migration each; `sync` plans and enqueues
|
|
107
|
+
* what is pending; `converge` brings the declared collections to their
|
|
108
|
+
* declared state.
|
|
109
|
+
*/
|
|
110
|
+
export const JOB_NAMES: Readonly<{ UP: 'up'; DOWN: 'down'; SYNC: 'sync'; CONVERGE: 'converge' }>;
|
|
111
|
+
/**
|
|
112
|
+
* Version stamped on every job's data as `v`. A worker accepts every version
|
|
113
|
+
* from {@link MIN_JOB_DATA_VERSION} up to its own and refuses a newer one —
|
|
114
|
+
* roll workers out before the producers that write a new version.
|
|
115
|
+
*/
|
|
116
|
+
export const JOB_DATA_VERSION: 1;
|
|
117
|
+
/** The oldest job data version a worker still accepts — moves only in a major release */
|
|
118
|
+
export const MIN_JOB_DATA_VERSION: 1;
|
|
119
|
+
export const DEFAULT_QUEUE_NAME: 'migronaut';
|
|
120
|
+
export const DEFAULT_SCHEDULER_ID: 'migronaut-sync';
|
|
121
|
+
/** Default id of a `schedule({ job: 'converge' })` schedule */
|
|
122
|
+
export const DEFAULT_CONVERGE_SCHEDULER_ID: 'migronaut-converge';
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Data of an `up` or `down` job. Stored in Redis — re-validated by the worker as untrusted input
|
|
126
|
+
* @experimental New in 2.1 — the shape may still change in a minor release (named in the CHANGELOG).
|
|
127
|
+
*/
|
|
128
|
+
export interface MigrationJobData {
|
|
129
|
+
v: 1;
|
|
130
|
+
direction: 'up' | 'down';
|
|
131
|
+
/** Bare migration filename */
|
|
132
|
+
migration: string;
|
|
133
|
+
/** The enqueue call this job belongs to — minted by the kit's `generateId`, a UUID by default */
|
|
134
|
+
groupId: string;
|
|
135
|
+
/** Position within the group, and the group's size */
|
|
136
|
+
index: number;
|
|
137
|
+
total: number;
|
|
138
|
+
/**
|
|
139
|
+
* `up`: the batch every job of the group stamps (peeked once at enqueue
|
|
140
|
+
* time). `down`: the batch the record carried, for information only.
|
|
141
|
+
*/
|
|
142
|
+
batch?: number;
|
|
143
|
+
/** Re-run an already-applied migration (`up` only) */
|
|
144
|
+
force?: true;
|
|
145
|
+
/**
|
|
146
|
+
* `false` skips the order guard for this job. Always written by the
|
|
147
|
+
* producer; a job without it (hand-added) gets the worker's default.
|
|
148
|
+
*/
|
|
149
|
+
ordered?: boolean;
|
|
150
|
+
/** SHA-256 of the migration file when the job was planned */
|
|
151
|
+
checksum?: string;
|
|
152
|
+
/** Who asked (≤ 128 characters) — carried by the jobs, stamped on the changelog / converge history */
|
|
153
|
+
requestedBy?: string;
|
|
154
|
+
/** Why (≤ 512 characters) — carried and stamped like `requestedBy` */
|
|
155
|
+
reason?: string;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Data of a `sync` job — what a schedule tick enqueues
|
|
160
|
+
* @experimental New in 2.1 — the shape may still change in a minor release (named in the CHANGELOG).
|
|
161
|
+
*/
|
|
162
|
+
export interface SyncJobData {
|
|
163
|
+
v: 1;
|
|
164
|
+
kind: 'sync';
|
|
165
|
+
/** Enqueue pending migrations only up to and including this file */
|
|
166
|
+
to?: string;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Data of a `converge` job. There is deliberately no `prune`: what may be
|
|
171
|
+
* dropped is decided by the definitions the worker loads, never by a payload.
|
|
172
|
+
* @experimental New in 2.1 — the shape may still change in a minor release (named in the CHANGELOG).
|
|
173
|
+
*/
|
|
174
|
+
export interface ConvergeJobData {
|
|
175
|
+
v: 1;
|
|
176
|
+
kind: 'converge';
|
|
177
|
+
/** The enqueue call it belongs to — the `up` group it ends, or its own */
|
|
178
|
+
groupId?: string;
|
|
179
|
+
/**
|
|
180
|
+
* `false` lets it run while migrations are pending. Always written by the
|
|
181
|
+
* producer; a job without it gets the worker's default (refuse).
|
|
182
|
+
*/
|
|
183
|
+
ordered?: boolean;
|
|
184
|
+
/** Who asked (≤ 128 characters) — carried by the jobs, stamped on the changelog / converge history */
|
|
185
|
+
requestedBy?: string;
|
|
186
|
+
/** Why (≤ 512 characters) — carried and stamped like `requestedBy` */
|
|
187
|
+
reason?: string;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* What a completed `up`/`down` job returns
|
|
192
|
+
* @experimental New in 2.1 — the shape may still change in a minor release (named in the CHANGELOG).
|
|
193
|
+
*/
|
|
194
|
+
export interface MigrationJobResult {
|
|
195
|
+
migration: string;
|
|
196
|
+
direction: 'up' | 'down';
|
|
197
|
+
/** `'skipped'`: already applied (up) or already reverted (down) — a duplicate job, not an error */
|
|
198
|
+
status: 'applied' | 'reverted' | 'skipped';
|
|
199
|
+
duration?: number;
|
|
200
|
+
batch?: number;
|
|
201
|
+
/** Correlation id of the run, matching the changelog record and the kit's events */
|
|
202
|
+
runId?: string;
|
|
203
|
+
reason?: string;
|
|
204
|
+
/** Time (ms) spent waiting for the MongoDB migration lock */
|
|
205
|
+
lockWaitMs: number;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* What a completed `sync` job returns
|
|
210
|
+
* @experimental New in 2.1 — the shape may still change in a minor release (named in the CHANGELOG).
|
|
211
|
+
*/
|
|
212
|
+
export interface SyncJobResult {
|
|
213
|
+
kind: 'sync';
|
|
214
|
+
groupId: string | null;
|
|
215
|
+
batch: number | null;
|
|
216
|
+
/** Number of migration jobs this tick added */
|
|
217
|
+
enqueued: number;
|
|
218
|
+
upToDate: boolean;
|
|
219
|
+
migrations: string[];
|
|
220
|
+
/** The converge job this tick added (`convergeAfterUp`), if any */
|
|
221
|
+
converge?: { jobId: string; deduplicated: boolean };
|
|
222
|
+
/**
|
|
223
|
+
* Present when the tick enqueued nothing because the next migration failed
|
|
224
|
+
* and its file has not changed since — a schedule's circuit breaker. A fix
|
|
225
|
+
* (a changed file) or an explicit `enqueueUp(name)` resumes the line.
|
|
226
|
+
*/
|
|
227
|
+
held?: { migration: string; reason: string; failedAt?: Date };
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* What a completed `converge` job returns — the kit's result, minus `dryRun`
|
|
232
|
+
* @experimental New in 2.1 — the shape may still change in a minor release (named in the CHANGELOG).
|
|
233
|
+
*/
|
|
234
|
+
export interface ConvergeJobResult {
|
|
235
|
+
kind: 'converge';
|
|
236
|
+
groupId?: string;
|
|
237
|
+
changed: number;
|
|
238
|
+
inSync: boolean;
|
|
239
|
+
collections: CollectionConvergeResult[];
|
|
240
|
+
unstable?: ConvergeUnstable[];
|
|
241
|
+
/**
|
|
242
|
+
* Atlas Search availability and the declared search indexes still building
|
|
243
|
+
* — when the worker's definitions declare search indexes. Whether the job
|
|
244
|
+
* waits for them is the worker kit's `waitForSearchIndexes`.
|
|
245
|
+
* @experimental New in 2.2
|
|
246
|
+
*/
|
|
247
|
+
search?: ConvergeSearchSummary;
|
|
248
|
+
runId?: string;
|
|
249
|
+
/** Time (ms) spent waiting for the MongoDB migration lock */
|
|
250
|
+
lockWaitMs: number;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* What a job reports through `job.updateProgress`
|
|
255
|
+
* @experimental New in 2.1 — the shape may still change in a minor release (named in the CHANGELOG).
|
|
256
|
+
*/
|
|
257
|
+
export interface MigrationJobProgress {
|
|
258
|
+
/** `search-wait` (New in 2.2): a converge job waiting for search index builds */
|
|
259
|
+
phase: 'lock-wait' | 'running' | 'search-wait' | 'completed' | 'failed';
|
|
260
|
+
migration?: string;
|
|
261
|
+
direction?: 'up' | 'down';
|
|
262
|
+
groupId?: string;
|
|
263
|
+
index?: number;
|
|
264
|
+
total?: number;
|
|
265
|
+
kind?: 'sync' | 'converge';
|
|
266
|
+
/** `lock-wait` only */
|
|
267
|
+
attempts?: number;
|
|
268
|
+
/** `lock-wait` and `search-wait` */
|
|
269
|
+
waitedMs?: number;
|
|
270
|
+
/**
|
|
271
|
+
* `search-wait` only — how many search indexes the wait is for
|
|
272
|
+
* @experimental New in 2.2
|
|
273
|
+
*/
|
|
274
|
+
searchIndexes?: number;
|
|
275
|
+
/**
|
|
276
|
+
* `failed` only — the typed error code, so nobody has to parse
|
|
277
|
+
* `failedReason`; `'UNKNOWN'` for an error that is not migronaut's.
|
|
278
|
+
*/
|
|
279
|
+
code?: MigronautErrorCode | 'UNKNOWN';
|
|
280
|
+
/**
|
|
281
|
+
* `completed` and `failed` — the run's correlation id, matching the changelog
|
|
282
|
+
* record and the kit's events. A failed job has no return value, so this is
|
|
283
|
+
* where its run id is found.
|
|
284
|
+
*/
|
|
285
|
+
runId?: string;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Per-job BullMQ options passed through to every migration job — retention and
|
|
290
|
+
* logging knobs. Anything that would reorder, delay or re-run a job is refused:
|
|
291
|
+
* the queue is first-in, first-out with a single attempt, on purpose.
|
|
292
|
+
*/
|
|
293
|
+
export interface MigrationJobOptions {
|
|
294
|
+
removeOnComplete?: boolean | number | { age?: number; count?: number };
|
|
295
|
+
removeOnFail?: boolean | number | { age?: number; count?: number };
|
|
296
|
+
keepLogs?: number;
|
|
297
|
+
stackTraceLimit?: number;
|
|
298
|
+
sizeLimit?: number;
|
|
299
|
+
attempts?: never;
|
|
300
|
+
backoff?: never;
|
|
301
|
+
delay?: never;
|
|
302
|
+
priority?: never;
|
|
303
|
+
lifo?: never;
|
|
304
|
+
jobId?: never;
|
|
305
|
+
deduplication?: never;
|
|
306
|
+
repeat?: never;
|
|
307
|
+
parent?: never;
|
|
308
|
+
[option: string]: unknown;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/** One job as handed to `queue.addBulk` */
|
|
312
|
+
export interface MigrationJobSpec {
|
|
313
|
+
name: 'up' | 'down';
|
|
314
|
+
data: MigrationJobData;
|
|
315
|
+
opts: { attempts: 1; deduplication: { id: string }; [option: string]: unknown };
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/** A converge job as handed to `queue.addBulk` */
|
|
319
|
+
export interface ConvergeJobSpec {
|
|
320
|
+
name: 'converge';
|
|
321
|
+
data: ConvergeJobData;
|
|
322
|
+
opts: { attempts: 1; deduplication: { id: string }; [option: string]: unknown };
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/** A planned, not yet enqueued, group */
|
|
326
|
+
export interface MigrationPlan {
|
|
327
|
+
/** Id of this enqueue call, in the kit's `generateId` format (a UUID by default) */
|
|
328
|
+
groupId: string;
|
|
329
|
+
direction: 'up' | 'down';
|
|
330
|
+
/** Shared batch of an `up` group; null for `down` and for an empty plan */
|
|
331
|
+
batch: number | null;
|
|
332
|
+
/** The files, in execution order */
|
|
333
|
+
migrations: string[];
|
|
334
|
+
jobs: MigrationJobSpec[];
|
|
335
|
+
/** The converge job that ends an `up` group — see `EnqueueUpOptions.converge` */
|
|
336
|
+
converge?: ConvergeJobSpec;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/** {@link parseJobData}'s normalized result */
|
|
340
|
+
export type ParsedJobData =
|
|
341
|
+
| {
|
|
342
|
+
kind: 'migration';
|
|
343
|
+
direction: 'up' | 'down';
|
|
344
|
+
migration: string;
|
|
345
|
+
groupId: string;
|
|
346
|
+
index: number;
|
|
347
|
+
total: number;
|
|
348
|
+
batch?: number;
|
|
349
|
+
force?: true;
|
|
350
|
+
ordered?: boolean;
|
|
351
|
+
}
|
|
352
|
+
| { kind: 'sync'; to?: string }
|
|
353
|
+
| { kind: 'converge'; groupId?: string; ordered?: boolean };
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* Validate a job read back from the queue and return a normalized copy.
|
|
357
|
+
* Throws `QueueJobInvalidError` for anything outside the contract.
|
|
358
|
+
*/
|
|
359
|
+
export function parseJobData(job: { id?: string; name: string; data: unknown }): ParsedJobData;
|
|
360
|
+
|
|
361
|
+
/** The deduplication id a migration's job carries — never contains `:` */
|
|
362
|
+
export function dedupId(direction: 'up' | 'down', migration: string): string;
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* Error codes a later attempt can get past with nothing fixed (lock busy or
|
|
366
|
+
* lost, database unreachable, run stopped). Every other `MigronautError` is
|
|
367
|
+
* failed without retry.
|
|
368
|
+
*/
|
|
369
|
+
export const RETRYABLE_CODES: readonly MigronautErrorCode[];
|
|
370
|
+
|
|
371
|
+
/** Whether the processor treats `error` as retryable — see {@link RETRYABLE_CODES} */
|
|
372
|
+
export function isRetryableError(error: unknown): boolean;
|
|
373
|
+
|
|
374
|
+
// ─── Options ───────────────────────────────────────────────────────────────────
|
|
375
|
+
|
|
376
|
+
/** How a job behaves when the MongoDB migration lock is held (a CLI run, a peer worker) */
|
|
377
|
+
export interface LockWaitOptions {
|
|
378
|
+
/** Default `'wait'` — unlike `runMigrations`, nothing is blocked on a job */
|
|
379
|
+
onLockHeld?: OnLockHeld;
|
|
380
|
+
/**
|
|
381
|
+
* Max time (ms) to wait without observing the holder make progress. Default
|
|
382
|
+
* 90000, or 1.5× the holder's lock TTL when that is longer
|
|
383
|
+
*/
|
|
384
|
+
lockWaitTimeoutMs?: number;
|
|
385
|
+
/** First poll interval (ms); polls back off, doubling, up to 5 s. Default 500 */
|
|
386
|
+
lockPollIntervalMs?: number;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/** Options for `enqueueUp` */
|
|
390
|
+
export interface EnqueueUpOptions {
|
|
391
|
+
/** Enqueue pending migrations up to and including this file */
|
|
392
|
+
to?: string;
|
|
393
|
+
/** Re-run an already-applied migration. Needs a filename */
|
|
394
|
+
force?: boolean;
|
|
395
|
+
/**
|
|
396
|
+
* Default `true`: each job refuses (`MigrationBlockedError`) while an
|
|
397
|
+
* earlier migration is still pending. `false` gives the plain single-file
|
|
398
|
+
* `up` of the CLI.
|
|
399
|
+
*/
|
|
400
|
+
ordered?: boolean;
|
|
401
|
+
/**
|
|
402
|
+
* End the group with a converge job, which runs once every migration of the
|
|
403
|
+
* group is applied (and refuses, as blocked, while one is not). Default: the
|
|
404
|
+
* kit's `convergeAfterUp` — a queue never fires the kit's own after-up hook,
|
|
405
|
+
* since each job is a single-file run. With nothing pending, a converge job
|
|
406
|
+
* is added only when a dry run finds the database out of step. Refused with
|
|
407
|
+
* a filename or `to`.
|
|
408
|
+
*/
|
|
409
|
+
converge?: boolean;
|
|
410
|
+
/** Who asked (≤ 128 characters) — carried by the jobs, stamped on the changelog / converge history */
|
|
411
|
+
requestedBy?: string;
|
|
412
|
+
/** Why (≤ 512 characters) — carried and stamped like `requestedBy` */
|
|
413
|
+
reason?: string;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/** Options for `enqueueConverge` */
|
|
417
|
+
export interface EnqueueConvergeOptions {
|
|
418
|
+
/** Default `true`: refuse while a migration is still pending. `false` converges anyway */
|
|
419
|
+
ordered?: boolean;
|
|
420
|
+
/** Who asked (≤ 128 characters) — carried by the jobs, stamped on the changelog / converge history */
|
|
421
|
+
requestedBy?: string;
|
|
422
|
+
/** Why (≤ 512 characters) — carried and stamped like `requestedBy` */
|
|
423
|
+
reason?: string;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
/** Options for `enqueueDown` */
|
|
427
|
+
export interface EnqueueDownOptions {
|
|
428
|
+
/** Revert this batch instead of the last one */
|
|
429
|
+
batch?: number;
|
|
430
|
+
/** Revert the last N applied migrations */
|
|
431
|
+
steps?: number;
|
|
432
|
+
/** Revert everything applied after this migration */
|
|
433
|
+
to?: string;
|
|
434
|
+
/**
|
|
435
|
+
* Default `true`: the rollback must be the top of the applied stack and each
|
|
436
|
+
* job refuses while a later-applied migration remains. `false` gives the
|
|
437
|
+
* CLI's unguarded `down`.
|
|
438
|
+
*/
|
|
439
|
+
ordered?: boolean;
|
|
440
|
+
/** Who asked (≤ 128 characters) — carried by the jobs, stamped on the changelog / converge history */
|
|
441
|
+
requestedBy?: string;
|
|
442
|
+
/** Why (≤ 512 characters) — carried and stamped like `requestedBy` */
|
|
443
|
+
reason?: string;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
/** Options for a group's `wait()` */
|
|
447
|
+
export interface WaitOptions {
|
|
448
|
+
/** One budget (ms) for the whole group. Default: no limit */
|
|
449
|
+
timeoutMs?: number;
|
|
450
|
+
/** A QueueEvents instance to listen on, when the facade was not given one */
|
|
451
|
+
queueEvents?: BullMQQueueEventsLike;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
/** What a group's `wait()` resolves with */
|
|
455
|
+
export interface GroupWaitResult {
|
|
456
|
+
groupId: string;
|
|
457
|
+
direction: 'up' | 'down';
|
|
458
|
+
batch: number | null;
|
|
459
|
+
/** One result per job, in group order */
|
|
460
|
+
results: MigrationJobResult[];
|
|
461
|
+
/** The group's converge job, when it had one */
|
|
462
|
+
converge?: ConvergeJobResult;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
/** Handle returned by `enqueueUp`/`enqueueDown` */
|
|
466
|
+
export interface MigrationGroup {
|
|
467
|
+
/** Id of this enqueue call, in the kit's `generateId` format (a UUID by default) */
|
|
468
|
+
groupId: string;
|
|
469
|
+
direction: 'up' | 'down';
|
|
470
|
+
/** The batch every job of an `up` group will stamp; null for `down` or when nothing was enqueued */
|
|
471
|
+
batch: number | null;
|
|
472
|
+
/** True when there was nothing to do — no job was added */
|
|
473
|
+
upToDate: boolean;
|
|
474
|
+
jobs: { id: string; migration: string; index: number }[];
|
|
475
|
+
/**
|
|
476
|
+
* Files whose job already existed in the queue (enqueued by a peer). Their
|
|
477
|
+
* `jobs[].id` is that existing job, so `wait()` simply joins it.
|
|
478
|
+
*/
|
|
479
|
+
deduplicated: string[];
|
|
480
|
+
/** The converge job ending the group, or null. `deduplicated`: a peer's identical job */
|
|
481
|
+
converge: { id: string; deduplicated: boolean } | null;
|
|
482
|
+
/**
|
|
483
|
+
* Resolve when every job has finished — the converge job last; reject with
|
|
484
|
+
* `QueueJobFailedError` at the first one that fails or outlives `timeoutMs`.
|
|
485
|
+
* Needs QueueEvents.
|
|
486
|
+
*/
|
|
487
|
+
wait(options?: WaitOptions): Promise<GroupWaitResult>;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
/** Handle returned by `enqueueConverge` */
|
|
491
|
+
export interface ConvergeHandle {
|
|
492
|
+
groupId: string;
|
|
493
|
+
jobId: string;
|
|
494
|
+
/** True when an identical converge job was already waiting — `jobId` is that one */
|
|
495
|
+
deduplicated: boolean;
|
|
496
|
+
/** Resolve with the job's result; reject with `QueueJobFailedError`. Needs QueueEvents */
|
|
497
|
+
wait(options?: WaitOptions): Promise<ConvergeJobResult>;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
/**
|
|
501
|
+
* Options for {@link MigrationQueue.schedule} — exactly one of `every` /
|
|
502
|
+
* `pattern`, for a `sync` schedule (the default) or a `converge` one.
|
|
503
|
+
*/
|
|
504
|
+
export type ScheduleOptions = (
|
|
505
|
+
| { every: number; pattern?: never }
|
|
506
|
+
| { pattern: string; every?: never }
|
|
507
|
+
) & {
|
|
508
|
+
/** Time zone for `pattern` */
|
|
509
|
+
tz?: string;
|
|
510
|
+
} & (
|
|
511
|
+
| {
|
|
512
|
+
/** Each tick plans and enqueues what is pending. The default */
|
|
513
|
+
job?: 'sync';
|
|
514
|
+
/** Scheduler id. Default `'migronaut-sync'` */
|
|
515
|
+
id?: string;
|
|
516
|
+
/** Each tick enqueues pending migrations only up to and including this file */
|
|
517
|
+
to?: string;
|
|
518
|
+
}
|
|
519
|
+
| {
|
|
520
|
+
/** Each tick enqueues a converge job */
|
|
521
|
+
job: 'converge';
|
|
522
|
+
/** Scheduler id. Default `'migronaut-converge'` */
|
|
523
|
+
id?: string;
|
|
524
|
+
to?: never;
|
|
525
|
+
}
|
|
526
|
+
);
|
|
527
|
+
|
|
528
|
+
/** Options for {@link MigrationQueue.startWorker} — passed to the Worker constructor */
|
|
529
|
+
export interface StartWorkerOptions {
|
|
530
|
+
/** Always 1; anything else is rejected */
|
|
531
|
+
concurrency?: 1;
|
|
532
|
+
/** BullMQ job lock (ms). Default 60000 */
|
|
533
|
+
lockDuration?: number;
|
|
534
|
+
stalledInterval?: number;
|
|
535
|
+
/** Default 1 */
|
|
536
|
+
maxStalledCount?: number;
|
|
537
|
+
autorun?: boolean;
|
|
538
|
+
[option: string]: unknown;
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
/** A job as plain, redacted data — what {@link MigrationQueue.getJob} returns */
|
|
542
|
+
export interface MigrationJobView {
|
|
543
|
+
id: string;
|
|
544
|
+
name: string;
|
|
545
|
+
/**
|
|
546
|
+
* The job's data as stored in Redis — redacted, but not validated: anything
|
|
547
|
+
* with write access to Redis can have put it there. A job the adapter
|
|
548
|
+
* enqueued has one of the contract's shapes; check before relying on it.
|
|
549
|
+
*/
|
|
550
|
+
data: unknown;
|
|
551
|
+
state: string;
|
|
552
|
+
/** As stored — see {@link MigrationJobProgress} for what the adapter writes */
|
|
553
|
+
progress: MigrationJobProgress | number;
|
|
554
|
+
returnvalue?: MigrationJobResult | SyncJobResult | ConvergeJobResult;
|
|
555
|
+
failedReason?: string;
|
|
556
|
+
attemptsMade: number;
|
|
557
|
+
timestamp?: number;
|
|
558
|
+
processedOn?: number;
|
|
559
|
+
finishedOn?: number;
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
// ─── Processor ─────────────────────────────────────────────────────────────────
|
|
563
|
+
|
|
564
|
+
/**
|
|
565
|
+
* What a worker accepts from a job's payload beyond "apply what is pending, in
|
|
566
|
+
* order". Anything that can write to Redis can enqueue, so the requests that
|
|
567
|
+
* go further are opt-in; a job asking for one that is off fails as
|
|
568
|
+
* `QUEUE_JOB_INVALID` (`context.permission`) before anything runs.
|
|
569
|
+
* @experimental New in 2.1 — the shape may still change in a minor release (named in the CHANGELOG).
|
|
570
|
+
*/
|
|
571
|
+
export interface MigrationJobPermissions {
|
|
572
|
+
/** Roll back (`down` jobs). Default `true` */
|
|
573
|
+
down?: boolean;
|
|
574
|
+
/** Re-run an applied migration (`force: true`). Default `false` */
|
|
575
|
+
force?: boolean;
|
|
576
|
+
/** Skip the order guard (`ordered: false`, on any job). Default `false` */
|
|
577
|
+
unordered?: boolean;
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
/** Options for {@link createMigrationProcessor} */
|
|
581
|
+
export interface CreateMigrationProcessorOptions {
|
|
582
|
+
/** Config for a MigratorKit the processor creates (and disconnects on `close()`) */
|
|
583
|
+
config?: Partial<MigronautConfig>;
|
|
584
|
+
kitOptions?: MigratorKitOptions;
|
|
585
|
+
/** A kit you own instead of `config` — never disconnected by the processor */
|
|
586
|
+
kit?: MigratorKit;
|
|
587
|
+
/** The queue the jobs arrive on. Needed only to process `sync` jobs, which enqueue into it */
|
|
588
|
+
queue?: BullMQQueueLike;
|
|
589
|
+
lockWait?: LockWaitOptions;
|
|
590
|
+
/** Order guard for jobs that do not say. Default `true` */
|
|
591
|
+
ordered?: boolean;
|
|
592
|
+
/** Options for the jobs a `sync` job enqueues */
|
|
593
|
+
jobOptions?: MigrationJobOptions;
|
|
594
|
+
/** What a job may ask for beyond the ordinary — see {@link MigrationJobPermissions} */
|
|
595
|
+
allow?: MigrationJobPermissions;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
/**
|
|
599
|
+
* The function a BullMQ Worker runs — pass it as the Worker's processor. It
|
|
600
|
+
* declares exactly three parameters, which is what makes BullMQ hand it the
|
|
601
|
+
* cancellation signal. Jobs are processed one at a time even when the Worker
|
|
602
|
+
* is configured for more.
|
|
603
|
+
*/
|
|
604
|
+
export interface MigrationProcessor {
|
|
605
|
+
(
|
|
606
|
+
job: BullMQJobLike<MigrationJobData | SyncJobData | ConvergeJobData>,
|
|
607
|
+
token?: string,
|
|
608
|
+
signal?: AbortSignal,
|
|
609
|
+
): Promise<MigrationJobResult | SyncJobResult | ConvergeJobResult>;
|
|
610
|
+
/** The kit running the jobs — subscribe to its events for metrics */
|
|
611
|
+
readonly kit: MigratorKit;
|
|
612
|
+
/**
|
|
613
|
+
* Stop taking the lock. Irreversible. A job that has not started its
|
|
614
|
+
* migration (or converge) yet — waiting for the lock, or fetched after the
|
|
615
|
+
* shutdown — is moved back to the head of the queue (`job.moveToWait`) and
|
|
616
|
+
* rejects with an error named `WaitingError`, which BullMQ records as
|
|
617
|
+
* neither failed nor completed; without a token (outside a Worker) it fails
|
|
618
|
+
* with `RunAbortedError`. Close your Worker first, or together with this: a
|
|
619
|
+
* job put back must not be fetched again by the same worker.
|
|
620
|
+
*/
|
|
621
|
+
shutdown(reason?: string): void;
|
|
622
|
+
/** `shutdown()`, let the job in flight settle, disconnect a kit the processor created */
|
|
623
|
+
close(): Promise<void>;
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
/**
|
|
627
|
+
* Build the processor for a Worker you construct yourself (a NestJS
|
|
628
|
+
* `@Processor`, BullMQ Pro, a shared worker process). Run it with
|
|
629
|
+
* `concurrency: 1`.
|
|
630
|
+
*/
|
|
631
|
+
export function createMigrationProcessor(
|
|
632
|
+
options?: CreateMigrationProcessorOptions,
|
|
633
|
+
): MigrationProcessor;
|
|
634
|
+
|
|
635
|
+
// ─── Producer building blocks ──────────────────────────────────────────────────
|
|
636
|
+
|
|
637
|
+
/** Plan an `up` group without enqueuing it */
|
|
638
|
+
export function planUpJobs(
|
|
639
|
+
kit: MigratorKit,
|
|
640
|
+
options?: EnqueueUpOptions & { filename?: string; jobOptions?: MigrationJobOptions },
|
|
641
|
+
): Promise<MigrationPlan>;
|
|
642
|
+
|
|
643
|
+
/** Plan a `down` group without enqueuing it */
|
|
644
|
+
export function planDownJobs(
|
|
645
|
+
kit: MigratorKit,
|
|
646
|
+
options?: EnqueueDownOptions & { filename?: string; jobOptions?: MigrationJobOptions },
|
|
647
|
+
): Promise<MigrationPlan>;
|
|
648
|
+
|
|
649
|
+
/** Enqueue pending migrations on a queue you own */
|
|
650
|
+
export function enqueueUp(
|
|
651
|
+
queue: BullMQQueueLike,
|
|
652
|
+
kit: MigratorKit,
|
|
653
|
+
options?: EnqueueUpOptions & {
|
|
654
|
+
filename?: string;
|
|
655
|
+
jobOptions?: MigrationJobOptions;
|
|
656
|
+
/** Lets the returned group's `wait()` work without further arguments */
|
|
657
|
+
queueEvents?: BullMQQueueEventsLike;
|
|
658
|
+
},
|
|
659
|
+
): Promise<MigrationGroup>;
|
|
660
|
+
|
|
661
|
+
/** Enqueue a rollback on a queue you own */
|
|
662
|
+
export function enqueueDown(
|
|
663
|
+
queue: BullMQQueueLike,
|
|
664
|
+
kit: MigratorKit,
|
|
665
|
+
options?: EnqueueDownOptions & {
|
|
666
|
+
filename?: string;
|
|
667
|
+
jobOptions?: MigrationJobOptions;
|
|
668
|
+
queueEvents?: BullMQQueueEventsLike;
|
|
669
|
+
},
|
|
670
|
+
): Promise<MigrationGroup>;
|
|
671
|
+
|
|
672
|
+
/** Enqueue a converge job on its own, on a queue you own */
|
|
673
|
+
export function enqueueConverge(
|
|
674
|
+
queue: BullMQQueueLike,
|
|
675
|
+
kit: MigratorKit,
|
|
676
|
+
options?: EnqueueConvergeOptions & {
|
|
677
|
+
jobOptions?: MigrationJobOptions;
|
|
678
|
+
/** Lets the returned handle's `wait()` work without further arguments */
|
|
679
|
+
queueEvents?: BullMQQueueEventsLike;
|
|
680
|
+
},
|
|
681
|
+
): Promise<ConvergeHandle>;
|
|
682
|
+
|
|
683
|
+
/** Wait for a group's jobs — what `MigrationGroup.wait()` calls */
|
|
684
|
+
export function waitForGroup(options: {
|
|
685
|
+
queue: BullMQQueueLike;
|
|
686
|
+
queueEvents: BullMQQueueEventsLike;
|
|
687
|
+
groupId: string;
|
|
688
|
+
direction: 'up' | 'down';
|
|
689
|
+
batch: number | null;
|
|
690
|
+
jobs: { id: string; migration: string }[];
|
|
691
|
+
/** The group's converge job, waited for last */
|
|
692
|
+
converge?: { id: string };
|
|
693
|
+
timeoutMs?: number;
|
|
694
|
+
}): Promise<GroupWaitResult>;
|
|
695
|
+
|
|
696
|
+
// ─── Facade ────────────────────────────────────────────────────────────────────
|
|
697
|
+
|
|
698
|
+
/** Options for {@link createMigrationQueue} */
|
|
699
|
+
export interface CreateMigrationQueueOptions<
|
|
700
|
+
Q extends BullMQQueueLike = BullMQQueueLike,
|
|
701
|
+
W extends BullMQWorkerLike = BullMQWorkerLike,
|
|
702
|
+
E extends BullMQQueueEventsLike = BullMQQueueEventsLike,
|
|
703
|
+
> {
|
|
704
|
+
/**
|
|
705
|
+
* BullMQ, from your own install — migronaut never imports it. Pass classes,
|
|
706
|
+
* or instances you already have (an injected instance is never closed by
|
|
707
|
+
* `close()`).
|
|
708
|
+
*/
|
|
709
|
+
bullmq: {
|
|
710
|
+
/** The `Queue` class, or a Queue instance */
|
|
711
|
+
Queue: BullMQQueueClass<Q> | Q;
|
|
712
|
+
/** The `Worker` class. Needed by `startWorker()`; a process that only enqueues can omit it */
|
|
713
|
+
Worker?: BullMQWorkerClass<W>;
|
|
714
|
+
/** The `QueueEvents` class, or an instance. Needed by `wait()` */
|
|
715
|
+
QueueEvents?: BullMQQueueEventsClass<E> | E;
|
|
716
|
+
/**
|
|
717
|
+
* BullMQ's own telemetry object — `new BullMQOtel({ tracerName })` from
|
|
718
|
+
* `bullmq-otel` — passed untouched to the Queue and the Worker this object
|
|
719
|
+
* constructs. It is what joins the trace of the process that enqueues to
|
|
720
|
+
* the one that applies. An injected Queue *instance* keeps whatever
|
|
721
|
+
* telemetry it was built with; `workerOptions.telemetry` and
|
|
722
|
+
* `startWorker({ telemetry })` override it for the worker.
|
|
723
|
+
*
|
|
724
|
+
* Not to be confused with the kit's own `config.telemetry` (a tracer and a
|
|
725
|
+
* meter for migronaut's spans and metrics).
|
|
726
|
+
*/
|
|
727
|
+
telemetry?: object;
|
|
728
|
+
};
|
|
729
|
+
/**
|
|
730
|
+
* BullMQ `connection` — connection options or your Redis client, passed
|
|
731
|
+
* through untouched and never closed. Required when anything is constructed
|
|
732
|
+
* from a class.
|
|
733
|
+
*/
|
|
734
|
+
connection?: unknown;
|
|
735
|
+
/** Config for the MigratorKit the queue creates (and disconnects on `close()`) */
|
|
736
|
+
config?: Partial<MigronautConfig>;
|
|
737
|
+
kitOptions?: MigratorKitOptions;
|
|
738
|
+
/** A kit you own instead of `config` — never disconnected by `close()` */
|
|
739
|
+
kit?: MigratorKit;
|
|
740
|
+
/**
|
|
741
|
+
* One queue per database. Default `'migronaut'` (or the injected queue's
|
|
742
|
+
* name — a different one is rejected)
|
|
743
|
+
*/
|
|
744
|
+
queueName?: string;
|
|
745
|
+
/** BullMQ key prefix. Default: the injected queue's own (a different one is rejected) */
|
|
746
|
+
prefix?: string;
|
|
747
|
+
jobOptions?: MigrationJobOptions;
|
|
748
|
+
/** Defaults for `startWorker()` */
|
|
749
|
+
workerOptions?: StartWorkerOptions;
|
|
750
|
+
/**
|
|
751
|
+
* Set the queue's global concurrency to 1 when the worker starts (BullMQ
|
|
752
|
+
* ≥ 5.9), so several pods take turns. Default `true`. The order never
|
|
753
|
+
* depends on it — the MongoDB lock and the order guard keep it; without it,
|
|
754
|
+
* a job that reaches the lock before an earlier one still in flight on
|
|
755
|
+
* another worker waits for that one (within its lock-wait budget).
|
|
756
|
+
*/
|
|
757
|
+
globalConcurrency?: boolean;
|
|
758
|
+
lockWait?: LockWaitOptions;
|
|
759
|
+
/**
|
|
760
|
+
* What the worker accepts from a job — and what `enqueueUp` / `enqueueDown` /
|
|
761
|
+
* `enqueueConverge` accept on this object, so a request its own worker would
|
|
762
|
+
* refuse fails at the call. Give every producer and worker the same policy.
|
|
763
|
+
*/
|
|
764
|
+
allow?: MigrationJobPermissions;
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
/**
|
|
768
|
+
* Migrations as a queue: one database's migrations, enqueued as one BullMQ job
|
|
769
|
+
* each and applied in order by a single-concurrency worker. Status reads go
|
|
770
|
+
* straight to MongoDB — the changelog, not the queue, is the source of truth.
|
|
771
|
+
*/
|
|
772
|
+
export class MigrationQueue<
|
|
773
|
+
Q extends BullMQQueueLike = BullMQQueueLike,
|
|
774
|
+
W extends BullMQWorkerLike = BullMQWorkerLike,
|
|
775
|
+
E extends BullMQQueueEventsLike = BullMQQueueEventsLike,
|
|
776
|
+
> {
|
|
777
|
+
constructor(options: CreateMigrationQueueOptions<Q, W, E>);
|
|
778
|
+
|
|
779
|
+
/** The kit behind the queue — `kit.on('migration:success', …)` for metrics */
|
|
780
|
+
readonly kit: MigratorKit;
|
|
781
|
+
/** Your Queue, with its own type */
|
|
782
|
+
readonly queue: Q;
|
|
783
|
+
/** The worker started by {@link startWorker}, if any */
|
|
784
|
+
readonly worker: W | undefined;
|
|
785
|
+
/** The QueueEvents in use — injected, or built on the first `wait()` */
|
|
786
|
+
readonly queueEvents: E | undefined;
|
|
787
|
+
readonly queueName: string;
|
|
788
|
+
/** The processor, for attaching to a Worker you construct yourself */
|
|
789
|
+
readonly processor: MigrationProcessor;
|
|
790
|
+
|
|
791
|
+
/**
|
|
792
|
+
* Enqueue pending migrations — all, up to `options.to`, or the one
|
|
793
|
+
* `filename` — as one job each, under a single shared batch.
|
|
794
|
+
*/
|
|
795
|
+
enqueueUp(filename?: string, options?: EnqueueUpOptions): Promise<MigrationGroup>;
|
|
796
|
+
/**
|
|
797
|
+
* Enqueue a rollback — the last batch, `options.batch`, the last
|
|
798
|
+
* `options.steps`, everything after `options.to`, or the one `filename` —
|
|
799
|
+
* newest applied first.
|
|
800
|
+
*/
|
|
801
|
+
enqueueDown(filename?: string, options?: EnqueueDownOptions): Promise<MigrationGroup>;
|
|
802
|
+
/**
|
|
803
|
+
* Enqueue a converge job: the declared collections brought to their declared
|
|
804
|
+
* state by the worker, under the MongoDB lock — refused while a migration is
|
|
805
|
+
* pending unless `ordered: false`. Experimental.
|
|
806
|
+
*/
|
|
807
|
+
enqueueConverge(options?: EnqueueConvergeOptions): Promise<ConvergeHandle>;
|
|
808
|
+
|
|
809
|
+
/** Full migration status, read from MongoDB */
|
|
810
|
+
status(): Promise<StatusRow[]>;
|
|
811
|
+
/** Migrations not applied yet */
|
|
812
|
+
pending(): Promise<StatusRow[]>;
|
|
813
|
+
audit(): Promise<AuditReport>;
|
|
814
|
+
/** Current holder of the MongoDB migration lock, or null */
|
|
815
|
+
lockInfo(): Promise<LockInfo | null>;
|
|
816
|
+
|
|
817
|
+
/**
|
|
818
|
+
* Start the worker (concurrency 1). Needs `bullmq.Worker`. Connects to
|
|
819
|
+
* MongoDB first, so an unreachable database fails here rather than on the
|
|
820
|
+
* first job. Calling it again resolves the same worker — or, after a start
|
|
821
|
+
* that failed, tries again.
|
|
822
|
+
*/
|
|
823
|
+
startWorker(options?: StartWorkerOptions): Promise<W>;
|
|
824
|
+
/** Stop workers from picking up new jobs; the job in flight finishes */
|
|
825
|
+
pause(): Promise<void>;
|
|
826
|
+
resume(): Promise<void>;
|
|
827
|
+
/** A job as plain, redacted data — or null */
|
|
828
|
+
getJob(id: string): Promise<MigrationJobView | null>;
|
|
829
|
+
|
|
830
|
+
/**
|
|
831
|
+
* Keep the database migrated on a schedule: each tick enqueues a `sync` job
|
|
832
|
+
* that plans and enqueues whatever is pending — or, with `job: 'converge'`,
|
|
833
|
+
* a converge job on a cadence of its own. Idempotent. BullMQ ≥ 5.16.
|
|
834
|
+
*/
|
|
835
|
+
schedule(options: ScheduleOptions): Promise<void>;
|
|
836
|
+
/**
|
|
837
|
+
* Remove a schedule — the sync one by default; pass
|
|
838
|
+
* {@link DEFAULT_CONVERGE_SCHEDULER_ID} (or your own id) for another.
|
|
839
|
+
* Resolves whether one existed.
|
|
840
|
+
*/
|
|
841
|
+
unschedule(id?: string): Promise<boolean>;
|
|
842
|
+
|
|
843
|
+
/**
|
|
844
|
+
* Stop fetching, stop taking the lock, let the worker finish its job, then
|
|
845
|
+
* close everything this object created. A job that had not started its
|
|
846
|
+
* migration is put back at the head of the queue for the next worker.
|
|
847
|
+
* `force` skips waiting for the job in flight — whose migration body, if
|
|
848
|
+
* running, keeps its connection: a kit this object created is disconnected
|
|
849
|
+
* once it settles. Injected instances, the Redis connection and an injected
|
|
850
|
+
* kit are left open. Idempotent.
|
|
851
|
+
*/
|
|
852
|
+
close(options?: { force?: boolean }): Promise<void>;
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
/** Create a {@link MigrationQueue} — `new MigrationQueue(options)` with inference */
|
|
856
|
+
export function createMigrationQueue<
|
|
857
|
+
Q extends BullMQQueueLike = BullMQQueueLike,
|
|
858
|
+
W extends BullMQWorkerLike = BullMQWorkerLike,
|
|
859
|
+
E extends BullMQQueueEventsLike = BullMQQueueEventsLike,
|
|
860
|
+
>(options: CreateMigrationQueueOptions<Q, W, E>): MigrationQueue<Q, W, E>;
|