Skip to content

Commit 1a23df7

Browse files
committed
add reset: true option
1 parent 2bcb307 commit 1a23df7

File tree

4 files changed

+34
-9
lines changed

4 files changed

+34
-9
lines changed

README.md

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -195,9 +195,11 @@ await migrations.runOne(ctx, internal.example.setDefaultValue);
195195

196196
- If it is already running it will refuse to start another duplicate worker.
197197
- If it had previously failed on some batch, it will continue from that batch
198-
unless you manually specify `cursor`.
198+
unless you manually specify `cursor` or `reset`.
199199
- If you provide an explicit `cursor` (`null` means to start at the beginning),
200200
it will start from there.
201+
- If you pass `reset: true`, it will restart the migration from the beginning
202+
for all migrations in the group (including any `next` migrations).
201203
- If you pass `true` for `dryRun` then it will run one batch and then throw,
202204
so no changes are committed, and you can see what it would have done.
203205
See [below](#test-a-migration-with-dryrun)
@@ -277,7 +279,15 @@ npx convex run migrations:runIt '{dryRun: true}'
277279

278280
### Restart a migration
279281

280-
Pass `null` for the `cursor` to force a migration to start over.
282+
Pass `reset: true` to force a migration to start over from the beginning.
283+
This will reset the cursor for all migrations in the group.
284+
285+
```sh
286+
npx convex run migrations:runIt '{reset: true}'
287+
```
288+
289+
Alternatively, you can pass `null` for the `cursor` to restart just the
290+
current migration:
281291

282292
```sh
283293
npx convex run migrations:runIt '{cursor: null}'

src/client/index.ts

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -185,15 +185,18 @@ export class Migrations<DataModel extends GenericDataModel> {
185185
)
186186
);
187187
}
188+
// Handle reset option: reset sets cursor to null for all migrations
189+
const cursor = args.reset ? null : args.cursor;
188190
let status: MigrationStatus;
189191
try {
190192
status = await ctx.runMutation(this.component.lib.migrate, {
191193
name,
192194
fnHandle,
193-
cursor: args.cursor,
195+
cursor,
194196
batchSize: args.batchSize,
195197
next,
196198
dryRun: args.dryRun ?? false,
199+
reset: args.reset,
197200
});
198201
} catch (e) {
199202
if (
@@ -231,8 +234,8 @@ export class Migrations<DataModel extends GenericDataModel> {
231234
* # Start or resume a migration. No-ops if it's already done:
232235
* npx convex run migrations:run '{"fn": "migrations:foo"}'
233236
*
234-
* # Restart a migration from a cursor (null is from the beginning):
235-
* npx convex run migrations:run '{"fn": "migrations:foo", "cursor": null }'
237+
* # Restart a migration from the beginning (also resets next migrations):
238+
* npx convex run migrations:run '{"fn": "migrations:foo", "reset": true }'
236239
*
237240
* # Dry run - runs one batch but doesn't schedule or commit changes.
238241
* # so you can see what it would do without committing the transaction.
@@ -310,7 +313,7 @@ export class Migrations<DataModel extends GenericDataModel> {
310313
"Running this from the CLI or dashboard? Here's some args to use:"
311314
);
312315
console.warn({
313-
"Dry run": '{ "dryRun": true, "cursor": null }',
316+
"Dry run": '{ "dryRun": true, "reset": true }',
314317
"For real": '{ "fn": "path/to/migrations:yourFnName" }',
315318
});
316319
}
@@ -457,6 +460,7 @@ export class Migrations<DataModel extends GenericDataModel> {
457460
* @param opts.cursor The cursor to start from.
458461
* null: start from the beginning.
459462
* undefined: start or resume from where it failed. If done, it won't restart.
463+
* @param opts.reset If true, restarts the migration from the beginning.
460464
* @param opts.batchSize The number of documents to process in a batch.
461465
* @param opts.dryRun If true, it will run a batch and then throw an error.
462466
* It's helpful to see what it would do without committing the transaction.
@@ -468,14 +472,16 @@ export class Migrations<DataModel extends GenericDataModel> {
468472
cursor?: string | null;
469473
batchSize?: number;
470474
dryRun?: boolean;
475+
reset?: boolean;
471476
}
472477
) {
473478
return ctx.runMutation(this.component.lib.migrate, {
474479
name: getFunctionName(fnRef),
475480
fnHandle: await createFunctionHandle(fnRef),
476-
cursor: opts?.cursor,
481+
cursor: opts?.reset ? null : opts?.cursor,
477482
batchSize: opts?.batchSize,
478483
dryRun: opts?.dryRun ?? false,
484+
reset: opts?.reset,
479485
});
480486
}
481487

@@ -649,6 +655,7 @@ function logStatusAndInstructions(
649655
cursor?: string | null;
650656
batchSize?: number;
651657
dryRun?: boolean;
658+
reset?: boolean;
652659
}
653660
) {
654661
const output: Record<string, unknown> = {};
@@ -703,7 +710,12 @@ function logStatusAndInstructions(
703710
prod: `--prod`,
704711
};
705712
} else {
706-
output["toStartOver"] = JSON.stringify({ ...args, cursor: null });
713+
// Suggest reset: true instead of cursor: null
714+
const { cursor: _cursor, ...argsWithoutCursor } = args;
715+
output["toStartOver"] = JSON.stringify({
716+
...argsWithoutCursor,
717+
reset: true,
718+
});
707719
if (status.next?.length) {
708720
output["toMonitorStatus"] = {
709721
cmd: `${run} --watch lib:getStatus`,

src/component/lib.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ const runMigrationArgs = {
3636
)
3737
),
3838
dryRun: v.boolean(),
39+
reset: v.optional(v.boolean()),
3940
};
4041

4142
export const migrate = mutation({
@@ -139,7 +140,7 @@ export const migrate = mutation({
139140
.query("migrations")
140141
.withIndex("name", (q) => q.eq("name", next[i]!.name))
141142
.unique();
142-
if (!doc || !doc.isDone) {
143+
if (args.reset || !doc || !doc.isDone) {
143144
const [nextFn, ...rest] = next.slice(i);
144145
if (nextFn) {
145146
await ctx.scheduler.runAfter(0, api.lib.migrate, {
@@ -148,6 +149,7 @@ export const migrate = mutation({
148149
next: rest,
149150
batchSize,
150151
dryRun,
152+
...(args.reset ? { reset: true, cursor: null } : {}),
151153
});
152154
}
153155
break;

src/shared.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export const migrationArgs = {
66
batchSize: v.optional(v.number()),
77
dryRun: v.optional(v.boolean()),
88
next: v.optional(v.array(v.string())),
9+
reset: v.optional(v.boolean()),
910
};
1011
export type MigrationArgs = ObjectType<typeof migrationArgs>;
1112

0 commit comments

Comments
 (0)