Skip to content

Commit c210299

Browse files
authored
Autobackfill migration state on update (#292)
* Autobackfill migration state on update * Migrate table to have some indexes * Don't check row count
1 parent 191f99d commit c210299

3 files changed

Lines changed: 65 additions & 0 deletions

File tree

api/db/migration-state-queries.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,20 @@ interface MigrationStateRow {
2929
last_error: string | null;
3030
}
3131

32+
// This is a blind backfill that only adds missing rows - it doesn't update existing ones
33+
export async function backfillMigrationState(
34+
client: ClientBase,
35+
platformMembershipId: string,
36+
bungieMembershipId: number,
37+
): Promise<void> {
38+
await client.query({
39+
name: 'backfill_migration_state',
40+
text: `insert into migration_state (platform_membership_id, membership_id, state) VALUES ($1, $2, $3)
41+
on conflict (platform_membership_id) do nothing`,
42+
values: [platformMembershipId, bungieMembershipId, MigrationState.Stately],
43+
});
44+
}
45+
3246
export async function getUsersToMigrate(client: ClientBase): Promise<number[]> {
3347
const results = await client.query<MigrationStateRow>({
3448
name: 'get_users_to_migrate',
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
'use strict';
2+
3+
var dbm;
4+
var type;
5+
var seed;
6+
7+
/**
8+
* We receive the dbmigrate dependency from dbmigrate initially.
9+
* This enables us to not have to rely on NODE_PATH.
10+
*/
11+
exports.setup = function (options, seedLink) {
12+
dbm = options.dbmigrate;
13+
type = dbm.dataType;
14+
seed = seedLink;
15+
};
16+
17+
exports.up = function (db, callback) {
18+
db.runSql(
19+
`ALTER TABLE migration_state ADD PRIMARY KEY (platform_membership_id);
20+
21+
CREATE INDEX migration_state_pending_idx ON migration_state (state, attempt_count)
22+
INCLUDE (platform_membership_id)
23+
WHERE state = 1 AND attempt_count < 3;`,
24+
callback,
25+
);
26+
};
27+
28+
exports.down = function (db, callback) {
29+
db.runSql(
30+
`DROP INDEX IF EXISTS migration_state_pending_idx;
31+
32+
ALTER TABLE migration_state DROP CONSTRAINT migration_state_pkey;`,
33+
callback,
34+
);
35+
};
36+
37+
exports._meta = {
38+
version: 1,
39+
};

api/routes/update.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import { captureMessage } from '@sentry/node';
22
import { chunk, groupBy, partition, sortBy } from 'es-toolkit';
33
import express from 'express';
44
import asyncHandler from 'express-async-handler';
5+
import { transaction } from '../db/index.js';
6+
import { backfillMigrationState } from '../db/migration-state-queries.js';
57
import { metrics } from '../metrics/index.js';
68
import { ApiApp } from '../shapes/app.js';
79
import { DestinyVersion } from '../shapes/general.js';
@@ -88,6 +90,16 @@ export const updateHandler = asyncHandler(async (req, res) => {
8890
return;
8991
}
9092

93+
// Do a conditional update of the migration state table in Postgres to mark
94+
// that we've seen this user and they are in the Stately migration state. This
95+
// makes sure new users get put into the migration table while we're
96+
// backfilling.
97+
if (platformMembershipId) {
98+
await transaction(async (client) => {
99+
backfillMigrationState(client, platformMembershipId ?? profileIds[0], bungieMembershipId);
100+
});
101+
}
102+
91103
// const migrationState = await readTransaction(async (client) =>
92104
// getMigrationState(client, bungieMembershipId),
93105
// );

0 commit comments

Comments
 (0)