@prairielearn/migrations 1.1.0 → 1.2.1
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/.turbo/turbo-build.log +2 -0
- package/CHANGELOG.md +19 -0
- package/README.md +145 -0
- package/dist/batched-migrations/batched-migration-job.d.ts +42 -0
- package/dist/batched-migrations/batched-migration-job.js +25 -0
- package/dist/batched-migrations/batched-migration-job.js.map +1 -0
- package/dist/batched-migrations/batched-migration-job.sql +12 -0
- package/dist/batched-migrations/batched-migration-runner.d.ts +29 -0
- package/dist/batched-migrations/batched-migration-runner.js +136 -0
- package/dist/batched-migrations/batched-migration-runner.js.map +1 -0
- package/dist/batched-migrations/batched-migration-runner.sql +93 -0
- package/dist/batched-migrations/batched-migration-runner.test.js +185 -0
- package/dist/batched-migrations/batched-migration-runner.test.js.map +1 -0
- package/dist/batched-migrations/batched-migration.d.ts +79 -0
- package/dist/batched-migrations/batched-migration.js +73 -0
- package/dist/batched-migrations/batched-migration.js.map +1 -0
- package/dist/batched-migrations/batched-migration.sql +95 -0
- package/dist/batched-migrations/batched-migrations-runner.d.ts +63 -0
- package/dist/batched-migrations/batched-migrations-runner.js +272 -0
- package/dist/batched-migrations/batched-migrations-runner.js.map +1 -0
- package/dist/batched-migrations/batched-migrations-runner.sql +35 -0
- package/dist/batched-migrations/batched-migrations-runner.test.js +116 -0
- package/dist/batched-migrations/batched-migrations-runner.test.js.map +1 -0
- package/dist/batched-migrations/fixtures/20230406184103_successful_migration.d.ts +9 -0
- package/dist/batched-migrations/fixtures/20230406184103_successful_migration.js +14 -0
- package/dist/batched-migrations/fixtures/20230406184103_successful_migration.js.map +1 -0
- package/dist/batched-migrations/fixtures/20230407230446_no_rows_migration.d.ts +8 -0
- package/dist/batched-migrations/fixtures/20230407230446_no_rows_migration.js +16 -0
- package/dist/batched-migrations/fixtures/20230407230446_no_rows_migration.js.map +1 -0
- package/dist/batched-migrations/index.d.ts +3 -0
- package/dist/batched-migrations/index.js +18 -0
- package/dist/batched-migrations/index.js.map +1 -0
- package/dist/index.d.ts +3 -12
- package/dist/index.js +15 -192
- package/dist/index.js.map +1 -1
- package/dist/load-migrations.d.ts +8 -0
- package/dist/load-migrations.js +60 -0
- package/dist/load-migrations.js.map +1 -0
- package/dist/load-migrations.test.d.ts +1 -0
- package/dist/{index.test.js → load-migrations.test.js} +12 -65
- package/dist/load-migrations.test.js.map +1 -0
- package/dist/migrations/fixtures/20230407210430_insert_user.d.ts +1 -0
- package/dist/migrations/fixtures/20230407210430_insert_user.js.map +1 -0
- package/dist/migrations/index.d.ts +1 -0
- package/dist/migrations/index.js +6 -0
- package/dist/migrations/index.js.map +1 -0
- package/dist/migrations/migrations.d.ts +6 -0
- package/dist/migrations/migrations.js +158 -0
- package/dist/migrations/migrations.js.map +1 -0
- package/dist/migrations/migrations.test.d.ts +1 -0
- package/dist/migrations/migrations.test.js +78 -0
- package/dist/migrations/migrations.test.js.map +1 -0
- package/package.json +15 -12
- package/schema-migrations/20230303193423_batched_migrations__create.sql +49 -0
- package/src/batched-migrations/batched-migration-job.sql +12 -0
- package/src/batched-migrations/batched-migration-job.ts +34 -0
- package/src/batched-migrations/batched-migration-runner.sql +93 -0
- package/src/batched-migrations/batched-migration-runner.test.ts +208 -0
- package/src/batched-migrations/batched-migration-runner.ts +215 -0
- package/src/batched-migrations/batched-migration.sql +95 -0
- package/src/batched-migrations/batched-migration.ts +129 -0
- package/src/batched-migrations/batched-migrations-runner.sql +35 -0
- package/src/batched-migrations/batched-migrations-runner.test.ts +111 -0
- package/src/batched-migrations/batched-migrations-runner.ts +327 -0
- package/src/batched-migrations/fixtures/20230406184103_successful_migration.ts +13 -0
- package/src/batched-migrations/fixtures/20230406184107_failing_migration.js +16 -0
- package/src/batched-migrations/fixtures/20230407230446_no_rows_migration.ts +15 -0
- package/src/batched-migrations/index.ts +21 -0
- package/src/index.ts +20 -201
- package/src/{index.test.ts → load-migrations.test.ts} +8 -73
- package/src/load-migrations.ts +76 -0
- package/src/migrations/index.ts +1 -0
- package/src/migrations/migrations.test.ts +80 -0
- package/src/migrations/migrations.ts +149 -0
- package/tsconfig.json +1 -1
- package/dist/fixtures/20230407210430_insert_user.js.map +0 -1
- package/dist/index.test.js.map +0 -1
- /package/dist/{fixtures/20230407210430_insert_user.d.ts → batched-migrations/batched-migration-runner.test.d.ts} +0 -0
- /package/dist/{index.test.d.ts → batched-migrations/batched-migrations-runner.test.d.ts} +0 -0
- /package/dist/{fixtures → migrations/fixtures}/20230407210409_create_users.sql +0 -0
- /package/dist/{fixtures → migrations/fixtures}/20230407210430_insert_user.js +0 -0
- /package/dist/{index.sql → migrations/migrations.sql} +0 -0
- /package/src/{fixtures → migrations/fixtures}/20230407210409_create_users.sql +0 -0
- /package/src/{fixtures → migrations/fixtures}/20230407210430_insert_user.ts +0 -0
- /package/src/{index.sql → migrations/migrations.sql} +0 -0
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
const chai_1 = require("chai");
|
|
27
|
+
const postgres_1 = require("@prairielearn/postgres");
|
|
28
|
+
const namedLocks = __importStar(require("@prairielearn/named-locks"));
|
|
29
|
+
const error = __importStar(require("@prairielearn/error"));
|
|
30
|
+
const batched_migration_1 = require("./batched-migration");
|
|
31
|
+
const batched_migration_job_1 = require("./batched-migration-job");
|
|
32
|
+
const batched_migration_runner_1 = require("./batched-migration-runner");
|
|
33
|
+
const index_1 = require("../index");
|
|
34
|
+
const postgresTestUtils = (0, postgres_1.makePostgresTestUtils)({
|
|
35
|
+
database: 'prairielearn_migrations',
|
|
36
|
+
});
|
|
37
|
+
function makeTestBatchMigration() {
|
|
38
|
+
let executionCount = 0;
|
|
39
|
+
let failingIds = [];
|
|
40
|
+
return (0, batched_migration_1.makeBatchedMigration)({
|
|
41
|
+
async getParameters() {
|
|
42
|
+
return {
|
|
43
|
+
min: 1n,
|
|
44
|
+
max: 10000n,
|
|
45
|
+
batchSize: 1000,
|
|
46
|
+
};
|
|
47
|
+
},
|
|
48
|
+
async execute(start, end) {
|
|
49
|
+
executionCount += 1;
|
|
50
|
+
const shouldFail = failingIds.some((id) => id >= start && id <= end);
|
|
51
|
+
if (shouldFail) {
|
|
52
|
+
// Throw an error with some data to make sure it gets persisted. We
|
|
53
|
+
// specifically use BigInt values here to make sure that they are
|
|
54
|
+
// correctly serialized to strings.
|
|
55
|
+
throw error.makeWithData('Execution failure', { start, end });
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
setFailingIds(ids) {
|
|
59
|
+
failingIds = ids;
|
|
60
|
+
},
|
|
61
|
+
get executionCount() {
|
|
62
|
+
return executionCount;
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
async function getBatchedMigration(migrationId) {
|
|
67
|
+
return (0, postgres_1.queryValidatedOneRow)('SELECT * FROM batched_migrations WHERE id = $id;', { id: migrationId }, batched_migration_1.BatchedMigrationRowSchema);
|
|
68
|
+
}
|
|
69
|
+
async function getBatchedMigrationJobs(migrationId) {
|
|
70
|
+
return (0, postgres_1.queryValidatedRows)('SELECT * FROM batched_migration_jobs WHERE batched_migration_id = $batched_migration_id ORDER BY id ASC;', { batched_migration_id: migrationId }, batched_migration_job_1.BatchedMigrationJobRowSchema);
|
|
71
|
+
}
|
|
72
|
+
async function resetFailedBatchedMigrationJobs(migrationId) {
|
|
73
|
+
await (0, postgres_1.queryAsync)("UPDATE batched_migration_jobs SET status = 'pending', updated_at = CURRENT_TIMESTAMP WHERE batched_migration_id = $batched_migration_id AND status = 'failed'", {
|
|
74
|
+
batched_migration_id: migrationId,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
async function insertTestBatchedMigration() {
|
|
78
|
+
const migrationImplementation = makeTestBatchMigration();
|
|
79
|
+
const parameters = await migrationImplementation.getParameters();
|
|
80
|
+
const migration = await (0, batched_migration_1.insertBatchedMigration)({
|
|
81
|
+
project: 'test',
|
|
82
|
+
filename: '20230406184103_test_batch_migration.js',
|
|
83
|
+
timestamp: '20230406184103',
|
|
84
|
+
batch_size: parameters.batchSize,
|
|
85
|
+
min_value: parameters.min,
|
|
86
|
+
max_value: parameters.max,
|
|
87
|
+
status: 'running',
|
|
88
|
+
});
|
|
89
|
+
if (!migration)
|
|
90
|
+
throw new Error('Failed to insert batched migration');
|
|
91
|
+
return migration;
|
|
92
|
+
}
|
|
93
|
+
describe('BatchedMigrationExecutor', () => {
|
|
94
|
+
before(async () => {
|
|
95
|
+
await postgresTestUtils.createDatabase();
|
|
96
|
+
await namedLocks.init(postgresTestUtils.getPoolConfig(), (err) => {
|
|
97
|
+
throw err;
|
|
98
|
+
});
|
|
99
|
+
await (0, index_1.init)([index_1.SCHEMA_MIGRATIONS_PATH], 'prairielearn_migrations');
|
|
100
|
+
});
|
|
101
|
+
beforeEach(async () => {
|
|
102
|
+
await postgresTestUtils.resetDatabase();
|
|
103
|
+
});
|
|
104
|
+
after(async () => {
|
|
105
|
+
await namedLocks.close();
|
|
106
|
+
await postgresTestUtils.dropDatabase();
|
|
107
|
+
});
|
|
108
|
+
it('runs one iteration of a batched migration', async () => {
|
|
109
|
+
const migration = await insertTestBatchedMigration();
|
|
110
|
+
const migrationImplementation = makeTestBatchMigration();
|
|
111
|
+
const executor = new batched_migration_runner_1.BatchedMigrationRunner(migration, migrationImplementation);
|
|
112
|
+
await executor.run({ iterations: 1 });
|
|
113
|
+
const jobs = await getBatchedMigrationJobs(migration.id);
|
|
114
|
+
chai_1.assert.lengthOf(jobs, 1);
|
|
115
|
+
const finalMigration = await getBatchedMigration(migration.id);
|
|
116
|
+
chai_1.assert.equal(finalMigration.status, 'running');
|
|
117
|
+
chai_1.assert.equal(migrationImplementation.executionCount, 1);
|
|
118
|
+
});
|
|
119
|
+
it('runs an entire batched migration', async () => {
|
|
120
|
+
const migration = await insertTestBatchedMigration();
|
|
121
|
+
const migrationImplementation = makeTestBatchMigration();
|
|
122
|
+
const runner = new batched_migration_runner_1.BatchedMigrationRunner(migration, migrationImplementation);
|
|
123
|
+
await runner.run();
|
|
124
|
+
const jobs = await getBatchedMigrationJobs(migration.id);
|
|
125
|
+
chai_1.assert.lengthOf(jobs, 10);
|
|
126
|
+
chai_1.assert.equal(jobs[0].min_value, 1n);
|
|
127
|
+
chai_1.assert.equal(jobs[0].max_value, 1000n);
|
|
128
|
+
chai_1.assert.equal(jobs.at(-1)?.min_value, 9001n);
|
|
129
|
+
chai_1.assert.equal(jobs.at(-1)?.max_value, 10000n);
|
|
130
|
+
chai_1.assert.isTrue(jobs.every((job) => job.started_at !== null));
|
|
131
|
+
chai_1.assert.isTrue(jobs.every((job) => job.finished_at !== null));
|
|
132
|
+
chai_1.assert.isTrue(jobs.every((job) => job.status === 'succeeded'));
|
|
133
|
+
chai_1.assert.isTrue(jobs.every((job) => job.attempts === 1));
|
|
134
|
+
const finalMigration = await getBatchedMigration(migration.id);
|
|
135
|
+
chai_1.assert.equal(finalMigration.status, 'succeeded');
|
|
136
|
+
});
|
|
137
|
+
it('handles failing execution', async () => {
|
|
138
|
+
let migration = await insertTestBatchedMigration();
|
|
139
|
+
const migrationImplementation = makeTestBatchMigration();
|
|
140
|
+
migrationImplementation.setFailingIds([1n, 5010n]);
|
|
141
|
+
const runner = new batched_migration_runner_1.BatchedMigrationRunner(migration, migrationImplementation);
|
|
142
|
+
await runner.run();
|
|
143
|
+
const jobs = await getBatchedMigrationJobs(migration.id);
|
|
144
|
+
const failedJobs = jobs.filter((job) => job.status === 'failed');
|
|
145
|
+
const successfulJobs = jobs.filter((job) => job.status === 'succeeded');
|
|
146
|
+
chai_1.assert.lengthOf(jobs, 10);
|
|
147
|
+
chai_1.assert.lengthOf(failedJobs, 2);
|
|
148
|
+
chai_1.assert.lengthOf(successfulJobs, 8);
|
|
149
|
+
chai_1.assert.equal(migrationImplementation.executionCount, 10);
|
|
150
|
+
chai_1.assert.isTrue(jobs.every((job) => job.attempts === 1));
|
|
151
|
+
failedJobs.forEach((job) => {
|
|
152
|
+
const jobData = job.data;
|
|
153
|
+
chai_1.assert.isObject(jobData);
|
|
154
|
+
chai_1.assert.isObject(jobData.error);
|
|
155
|
+
chai_1.assert.hasAllKeys(jobData.error, ['name', 'message', 'stack', 'data']);
|
|
156
|
+
chai_1.assert.equal(jobData.error.name, 'Error');
|
|
157
|
+
chai_1.assert.equal(jobData.error.message, 'Execution failure');
|
|
158
|
+
chai_1.assert.equal(jobData.error.data.start, job.min_value.toString());
|
|
159
|
+
chai_1.assert.equal(jobData.error.data.end, job.max_value.toString());
|
|
160
|
+
});
|
|
161
|
+
const failedMigration = await getBatchedMigration(migration.id);
|
|
162
|
+
chai_1.assert.equal(failedMigration.status, 'failed');
|
|
163
|
+
// Retry the failed jobs; ensure they succeed this time.
|
|
164
|
+
await resetFailedBatchedMigrationJobs(migration.id);
|
|
165
|
+
migration = await (0, batched_migration_1.updateBatchedMigrationStatus)(migration.id, 'running');
|
|
166
|
+
migrationImplementation.setFailingIds([]);
|
|
167
|
+
const retryRunner = new batched_migration_runner_1.BatchedMigrationRunner(migration, migrationImplementation);
|
|
168
|
+
await retryRunner.run();
|
|
169
|
+
const finalJobs = await getBatchedMigrationJobs(migration.id);
|
|
170
|
+
const finalFailedJobs = finalJobs.filter((job) => job.status === 'failed');
|
|
171
|
+
const finalSuccessfulJobs = finalJobs.filter((job) => job.status === 'succeeded');
|
|
172
|
+
const retriedJobs = finalJobs.filter((job) => job.attempts === 2);
|
|
173
|
+
chai_1.assert.lengthOf(finalJobs, 10);
|
|
174
|
+
chai_1.assert.lengthOf(finalFailedJobs, 0);
|
|
175
|
+
chai_1.assert.lengthOf(finalSuccessfulJobs, 10);
|
|
176
|
+
chai_1.assert.lengthOf(retriedJobs, 2);
|
|
177
|
+
chai_1.assert.isTrue(finalJobs.every((job) => job.data === null));
|
|
178
|
+
migration = await getBatchedMigration(migration.id);
|
|
179
|
+
chai_1.assert.equal(migration.status, 'succeeded');
|
|
180
|
+
// The runner should have run only the previously failed jobs, which
|
|
181
|
+
// works out to 2 additional execution.
|
|
182
|
+
chai_1.assert.equal(migrationImplementation.executionCount, 12);
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
//# sourceMappingURL=batched-migration-runner.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"batched-migration-runner.test.js","sourceRoot":"","sources":["../../src/batched-migrations/batched-migration-runner.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const BatchedMigrationStatusSchema: z.ZodEnum<["pending", "paused", "running", "finalizing", "failed", "succeeded"]>;
|
|
3
|
+
export type BatchedMigrationStatus = z.infer<typeof BatchedMigrationStatusSchema>;
|
|
4
|
+
export declare const BatchedMigrationRowSchema: z.ZodObject<{
|
|
5
|
+
id: z.ZodString;
|
|
6
|
+
project: z.ZodString;
|
|
7
|
+
filename: z.ZodString;
|
|
8
|
+
timestamp: z.ZodString;
|
|
9
|
+
batch_size: z.ZodNumber;
|
|
10
|
+
min_value: z.ZodBigInt;
|
|
11
|
+
max_value: z.ZodBigInt;
|
|
12
|
+
status: z.ZodEnum<["pending", "paused", "running", "finalizing", "failed", "succeeded"]>;
|
|
13
|
+
created_at: z.ZodDate;
|
|
14
|
+
updated_at: z.ZodDate;
|
|
15
|
+
started_at: z.ZodNullable<z.ZodDate>;
|
|
16
|
+
}, "strip", z.ZodTypeAny, {
|
|
17
|
+
filename: string;
|
|
18
|
+
timestamp: string;
|
|
19
|
+
project: string;
|
|
20
|
+
status: "pending" | "paused" | "running" | "finalizing" | "failed" | "succeeded";
|
|
21
|
+
id: string;
|
|
22
|
+
batch_size: number;
|
|
23
|
+
min_value: bigint;
|
|
24
|
+
max_value: bigint;
|
|
25
|
+
created_at: Date;
|
|
26
|
+
updated_at: Date;
|
|
27
|
+
started_at: Date | null;
|
|
28
|
+
}, {
|
|
29
|
+
filename: string;
|
|
30
|
+
timestamp: string;
|
|
31
|
+
project: string;
|
|
32
|
+
status: "pending" | "paused" | "running" | "finalizing" | "failed" | "succeeded";
|
|
33
|
+
id: string;
|
|
34
|
+
batch_size: number;
|
|
35
|
+
min_value: bigint;
|
|
36
|
+
max_value: bigint;
|
|
37
|
+
created_at: Date;
|
|
38
|
+
updated_at: Date;
|
|
39
|
+
started_at: Date | null;
|
|
40
|
+
}>;
|
|
41
|
+
export type BatchedMigrationRow = z.infer<typeof BatchedMigrationRowSchema>;
|
|
42
|
+
export interface BatchedMigrationParameters {
|
|
43
|
+
min?: bigint | null;
|
|
44
|
+
max: bigint | null;
|
|
45
|
+
batchSize?: number;
|
|
46
|
+
}
|
|
47
|
+
export interface BatchedMigrationImplementation {
|
|
48
|
+
getParameters(): Promise<BatchedMigrationParameters>;
|
|
49
|
+
execute(start: bigint, end: bigint): Promise<void>;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Identity function that helps to write correct batched migrations.
|
|
53
|
+
*/
|
|
54
|
+
export declare function makeBatchedMigration<T extends BatchedMigrationImplementation>(fns: T): T;
|
|
55
|
+
export declare function validateBatchedMigrationImplementation(fns: BatchedMigrationImplementation): asserts fns is BatchedMigrationImplementation;
|
|
56
|
+
type NewBatchedMigration = Pick<BatchedMigrationRow, 'project' | 'filename' | 'timestamp' | 'batch_size' | 'min_value' | 'max_value' | 'status'>;
|
|
57
|
+
/**
|
|
58
|
+
* Inserts a new batched migration. If one already exists for the given
|
|
59
|
+
* project/timestamp pair, returns null, otherwise returns the inserted row.
|
|
60
|
+
*/
|
|
61
|
+
export declare function insertBatchedMigration(migration: NewBatchedMigration): Promise<BatchedMigrationRow | null>;
|
|
62
|
+
export declare function selectAllBatchedMigrations(project: string): Promise<{
|
|
63
|
+
filename: string;
|
|
64
|
+
timestamp: string;
|
|
65
|
+
project: string;
|
|
66
|
+
status: "pending" | "paused" | "running" | "finalizing" | "failed" | "succeeded";
|
|
67
|
+
id: string;
|
|
68
|
+
batch_size: number;
|
|
69
|
+
min_value: bigint;
|
|
70
|
+
max_value: bigint;
|
|
71
|
+
created_at: Date;
|
|
72
|
+
updated_at: Date;
|
|
73
|
+
started_at: Date | null;
|
|
74
|
+
}[]>;
|
|
75
|
+
export declare function selectBatchedMigration(project: string, id: string): Promise<BatchedMigrationRow>;
|
|
76
|
+
export declare function selectBatchedMigrationForTimestamp(project: string, timestamp: string): Promise<BatchedMigrationRow>;
|
|
77
|
+
export declare function updateBatchedMigrationStatus(id: string, status: BatchedMigrationStatus): Promise<BatchedMigrationRow>;
|
|
78
|
+
export declare function retryFailedBatchedMigrationJobs(project: string, id: string): Promise<void>;
|
|
79
|
+
export {};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.retryFailedBatchedMigrationJobs = exports.updateBatchedMigrationStatus = exports.selectBatchedMigrationForTimestamp = exports.selectBatchedMigration = exports.selectAllBatchedMigrations = exports.insertBatchedMigration = exports.validateBatchedMigrationImplementation = exports.makeBatchedMigration = exports.BatchedMigrationRowSchema = exports.BatchedMigrationStatusSchema = void 0;
|
|
4
|
+
const postgres_1 = require("@prairielearn/postgres");
|
|
5
|
+
const zod_1 = require("zod");
|
|
6
|
+
const sql = (0, postgres_1.loadSqlEquiv)(__filename);
|
|
7
|
+
exports.BatchedMigrationStatusSchema = zod_1.z.enum([
|
|
8
|
+
'pending',
|
|
9
|
+
'paused',
|
|
10
|
+
'running',
|
|
11
|
+
'finalizing',
|
|
12
|
+
'failed',
|
|
13
|
+
'succeeded',
|
|
14
|
+
]);
|
|
15
|
+
exports.BatchedMigrationRowSchema = zod_1.z.object({
|
|
16
|
+
id: zod_1.z.string(),
|
|
17
|
+
project: zod_1.z.string(),
|
|
18
|
+
filename: zod_1.z.string(),
|
|
19
|
+
timestamp: zod_1.z.string(),
|
|
20
|
+
batch_size: zod_1.z.number(),
|
|
21
|
+
min_value: zod_1.z.bigint({ coerce: true }),
|
|
22
|
+
max_value: zod_1.z.bigint({ coerce: true }),
|
|
23
|
+
status: exports.BatchedMigrationStatusSchema,
|
|
24
|
+
created_at: zod_1.z.date(),
|
|
25
|
+
updated_at: zod_1.z.date(),
|
|
26
|
+
started_at: zod_1.z.date().nullable(),
|
|
27
|
+
});
|
|
28
|
+
/**
|
|
29
|
+
* Identity function that helps to write correct batched migrations.
|
|
30
|
+
*/
|
|
31
|
+
function makeBatchedMigration(fns) {
|
|
32
|
+
validateBatchedMigrationImplementation(fns);
|
|
33
|
+
return fns;
|
|
34
|
+
}
|
|
35
|
+
exports.makeBatchedMigration = makeBatchedMigration;
|
|
36
|
+
function validateBatchedMigrationImplementation(fns) {
|
|
37
|
+
if (typeof fns.getParameters !== 'function') {
|
|
38
|
+
throw new Error('getParameters() must be a function');
|
|
39
|
+
}
|
|
40
|
+
if (typeof fns.execute !== 'function') {
|
|
41
|
+
throw new Error('execute() must be a function');
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
exports.validateBatchedMigrationImplementation = validateBatchedMigrationImplementation;
|
|
45
|
+
/**
|
|
46
|
+
* Inserts a new batched migration. If one already exists for the given
|
|
47
|
+
* project/timestamp pair, returns null, otherwise returns the inserted row.
|
|
48
|
+
*/
|
|
49
|
+
async function insertBatchedMigration(migration) {
|
|
50
|
+
return (0, postgres_1.queryValidatedZeroOrOneRow)(sql.insert_batched_migration, migration, exports.BatchedMigrationRowSchema);
|
|
51
|
+
}
|
|
52
|
+
exports.insertBatchedMigration = insertBatchedMigration;
|
|
53
|
+
async function selectAllBatchedMigrations(project) {
|
|
54
|
+
return (0, postgres_1.queryValidatedRows)(sql.select_all_batched_migrations, { project }, exports.BatchedMigrationRowSchema);
|
|
55
|
+
}
|
|
56
|
+
exports.selectAllBatchedMigrations = selectAllBatchedMigrations;
|
|
57
|
+
async function selectBatchedMigration(project, id) {
|
|
58
|
+
return (0, postgres_1.queryValidatedOneRow)(sql.select_batched_migration, { project, id }, exports.BatchedMigrationRowSchema);
|
|
59
|
+
}
|
|
60
|
+
exports.selectBatchedMigration = selectBatchedMigration;
|
|
61
|
+
async function selectBatchedMigrationForTimestamp(project, timestamp) {
|
|
62
|
+
return (0, postgres_1.queryValidatedOneRow)(sql.select_batched_migration_for_timestamp, { project, timestamp }, exports.BatchedMigrationRowSchema);
|
|
63
|
+
}
|
|
64
|
+
exports.selectBatchedMigrationForTimestamp = selectBatchedMigrationForTimestamp;
|
|
65
|
+
async function updateBatchedMigrationStatus(id, status) {
|
|
66
|
+
return (0, postgres_1.queryValidatedOneRow)(sql.update_batched_migration_status, { id, status }, exports.BatchedMigrationRowSchema);
|
|
67
|
+
}
|
|
68
|
+
exports.updateBatchedMigrationStatus = updateBatchedMigrationStatus;
|
|
69
|
+
async function retryFailedBatchedMigrationJobs(project, id) {
|
|
70
|
+
await (0, postgres_1.queryAsync)(sql.retry_failed_jobs, { project, id });
|
|
71
|
+
}
|
|
72
|
+
exports.retryFailedBatchedMigrationJobs = retryFailedBatchedMigrationJobs;
|
|
73
|
+
//# sourceMappingURL=batched-migration.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"batched-migration.js","sourceRoot":"","sources":["../../src/batched-migrations/batched-migration.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
-- BLOCK insert_batched_migration
|
|
2
|
+
INSERT INTO
|
|
3
|
+
batched_migrations (
|
|
4
|
+
project,
|
|
5
|
+
filename,
|
|
6
|
+
timestamp,
|
|
7
|
+
batch_size,
|
|
8
|
+
min_value,
|
|
9
|
+
max_value,
|
|
10
|
+
status,
|
|
11
|
+
started_at
|
|
12
|
+
)
|
|
13
|
+
VALUES
|
|
14
|
+
(
|
|
15
|
+
$project,
|
|
16
|
+
$filename,
|
|
17
|
+
$timestamp,
|
|
18
|
+
$batch_size,
|
|
19
|
+
$min_value,
|
|
20
|
+
$max_value,
|
|
21
|
+
$status,
|
|
22
|
+
-- If the migration is marked as already having succeeded, set `started_at`
|
|
23
|
+
-- since the migration did technically start.
|
|
24
|
+
CASE
|
|
25
|
+
WHEN $status::enum_batched_migration_status = 'succeeded' THEN CURRENT_TIMESTAMP
|
|
26
|
+
ELSE NULL
|
|
27
|
+
END
|
|
28
|
+
)
|
|
29
|
+
ON CONFLICT DO NOTHING
|
|
30
|
+
RETURNING
|
|
31
|
+
*;
|
|
32
|
+
|
|
33
|
+
-- BLOCK select_all_batched_migrations
|
|
34
|
+
SELECT
|
|
35
|
+
*
|
|
36
|
+
FROM
|
|
37
|
+
batched_migrations
|
|
38
|
+
WHERE
|
|
39
|
+
project = $project
|
|
40
|
+
ORDER BY
|
|
41
|
+
id ASC;
|
|
42
|
+
|
|
43
|
+
-- BLOCK select_batched_migration
|
|
44
|
+
SELECT
|
|
45
|
+
*
|
|
46
|
+
FROM
|
|
47
|
+
batched_migrations
|
|
48
|
+
WHERE
|
|
49
|
+
project = $project
|
|
50
|
+
AND id = $id;
|
|
51
|
+
|
|
52
|
+
-- BLOCK select_batched_migration_for_timestamp
|
|
53
|
+
SELECT
|
|
54
|
+
*
|
|
55
|
+
FROM
|
|
56
|
+
batched_migrations
|
|
57
|
+
WHERE
|
|
58
|
+
project = $project
|
|
59
|
+
AND timestamp = $timestamp;
|
|
60
|
+
|
|
61
|
+
-- BLOCK update_batched_migration_status
|
|
62
|
+
UPDATE batched_migrations
|
|
63
|
+
SET
|
|
64
|
+
status = $status,
|
|
65
|
+
updated_at = CURRENT_TIMESTAMP
|
|
66
|
+
WHERE
|
|
67
|
+
id = $id
|
|
68
|
+
RETURNING
|
|
69
|
+
*;
|
|
70
|
+
|
|
71
|
+
-- BLOCK retry_failed_jobs
|
|
72
|
+
WITH
|
|
73
|
+
updated_batched_migration AS (
|
|
74
|
+
UPDATE batched_migrations
|
|
75
|
+
SET
|
|
76
|
+
status = 'running',
|
|
77
|
+
started_at = CURRENT_TIMESTAMP,
|
|
78
|
+
updated_at = CURRENT_TIMESTAMP
|
|
79
|
+
WHERE
|
|
80
|
+
project = $project
|
|
81
|
+
AND id = $id
|
|
82
|
+
RETURNING
|
|
83
|
+
*
|
|
84
|
+
)
|
|
85
|
+
UPDATE batched_migration_jobs
|
|
86
|
+
SET
|
|
87
|
+
status = 'pending',
|
|
88
|
+
started_at = NULL,
|
|
89
|
+
finished_at = NULL,
|
|
90
|
+
updated_at = CURRENT_TIMESTAMP
|
|
91
|
+
FROM
|
|
92
|
+
updated_batched_migration
|
|
93
|
+
WHERE
|
|
94
|
+
batched_migration_id = updated_batched_migration.id
|
|
95
|
+
AND batched_migration_jobs.status = 'failed';
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import EventEmitter from 'node:events';
|
|
3
|
+
interface BatchedMigrationRunnerOptions {
|
|
4
|
+
project: string;
|
|
5
|
+
directories: string[];
|
|
6
|
+
}
|
|
7
|
+
interface BatchedMigrationStartOptions {
|
|
8
|
+
workDurationMs?: number;
|
|
9
|
+
sleepDurationMs?: number;
|
|
10
|
+
}
|
|
11
|
+
interface BatchedMigrationFinalizeOptions {
|
|
12
|
+
logProgress?: boolean;
|
|
13
|
+
}
|
|
14
|
+
export declare class BatchedMigrationsRunner extends EventEmitter {
|
|
15
|
+
private readonly options;
|
|
16
|
+
private readonly lockName;
|
|
17
|
+
private running;
|
|
18
|
+
private migrationFiles;
|
|
19
|
+
private abortController;
|
|
20
|
+
constructor(options: BatchedMigrationRunnerOptions);
|
|
21
|
+
private lockNameForTimestamp;
|
|
22
|
+
private getMigrationFiles;
|
|
23
|
+
private getMigrationForIdentifier;
|
|
24
|
+
/**
|
|
25
|
+
* Loads the implementation for the migration with the given identifier. The identifier
|
|
26
|
+
* must start with a 14-character timestamp. It may optionally be followed by
|
|
27
|
+
* an underscore with additional characters, which are ignored. These should
|
|
28
|
+
* typically be used to provide a human-readable name for the migration.
|
|
29
|
+
*/
|
|
30
|
+
private loadMigrationImplementation;
|
|
31
|
+
enqueueBatchedMigration(identifier: string): Promise<void>;
|
|
32
|
+
finalizeBatchedMigration(identifier: string, options?: BatchedMigrationFinalizeOptions): Promise<void>;
|
|
33
|
+
start(options?: BatchedMigrationStartOptions): void;
|
|
34
|
+
loop({ workDurationMs, sleepDurationMs }: BatchedMigrationStartOptions): Promise<void>;
|
|
35
|
+
private getOrStartMigration;
|
|
36
|
+
maybePerformWork(durationMs: number): Promise<boolean>;
|
|
37
|
+
stop(): Promise<void>;
|
|
38
|
+
}
|
|
39
|
+
export declare function initBatchedMigrations(options: BatchedMigrationRunnerOptions): BatchedMigrationsRunner;
|
|
40
|
+
export declare function startBatchedMigrations(options?: BatchedMigrationStartOptions): BatchedMigrationsRunner;
|
|
41
|
+
export declare function stopBatchedMigrations(): Promise<void>;
|
|
42
|
+
/**
|
|
43
|
+
* Given a batched migration identifier like `20230406184103_migration`,
|
|
44
|
+
* enqueues it for execution by creating a row in the `batched_migrations`
|
|
45
|
+
* table.
|
|
46
|
+
*
|
|
47
|
+
* Despite taking a full identifier, only the timestamp is used to uniquely
|
|
48
|
+
* identify the batched migration. The remaining part is just used to make
|
|
49
|
+
* calls more human-readable.
|
|
50
|
+
*
|
|
51
|
+
* @param identifier The identifier of the batched migration to enqueue.
|
|
52
|
+
*/
|
|
53
|
+
export declare function enqueueBatchedMigration(identifier: string): Promise<void>;
|
|
54
|
+
/**
|
|
55
|
+
* Given a batched migration identifier like `20230406184103_migration`,
|
|
56
|
+
* synchronously runs it to completion. An error will be thrown if the final
|
|
57
|
+
* status of the migration is not `succeeded`.
|
|
58
|
+
*
|
|
59
|
+
* @param identifier The identifier of the batched migration to finalize.
|
|
60
|
+
* @param options Options for finalizing the batched migration.
|
|
61
|
+
*/
|
|
62
|
+
export declare function finalizeBatchedMigration(identifier: string, options?: BatchedMigrationFinalizeOptions): Promise<void>;
|
|
63
|
+
export {};
|