velocious 1.0.628 → 1.0.629
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 +1 -1
- package/build/background-jobs/adapter.js +16 -0
- package/build/background-jobs/main.js +219 -22
- package/build/background-jobs/store.js +128 -19
- package/build/background-jobs/types.js +7 -0
- package/build/src/background-jobs/adapter.d.ts +17 -0
- package/build/src/background-jobs/adapter.d.ts.map +1 -1
- package/build/src/background-jobs/adapter.js +15 -1
- package/build/src/background-jobs/main.d.ts +71 -1
- package/build/src/background-jobs/main.d.ts.map +1 -1
- package/build/src/background-jobs/main.js +211 -24
- package/build/src/background-jobs/store.d.ts +44 -0
- package/build/src/background-jobs/store.d.ts.map +1 -1
- package/build/src/background-jobs/store.js +117 -19
- package/build/src/background-jobs/types.d.ts +25 -0
- package/build/src/background-jobs/types.d.ts.map +1 -1
- package/build/src/background-jobs/types.js +8 -1
- package/package.json +1 -1
- package/src/background-jobs/adapter.js +16 -0
- package/src/background-jobs/main.js +219 -22
- package/src/background-jobs/store.js +128 -19
- package/src/background-jobs/types.js +7 -0
|
@@ -43,6 +43,13 @@ import {
|
|
|
43
43
|
* @property {number | null} timeoutMs - Per-job timeout override, or null when omitted.
|
|
44
44
|
*/
|
|
45
45
|
|
|
46
|
+
/**
|
|
47
|
+
* BackgroundJobOrphanSelection type.
|
|
48
|
+
* @typedef {object} BackgroundJobOrphanSelection
|
|
49
|
+
* @property {Record<string, ReturnType<typeof JSON.parse>>} conditions - Exact update fence.
|
|
50
|
+
* @property {import("./types.js").BackgroundJobRow} job - Selected active handoff.
|
|
51
|
+
*/
|
|
52
|
+
|
|
46
53
|
/**
|
|
47
54
|
* BackgroundJobTransactionSerializationOptions type.
|
|
48
55
|
* @typedef {object} BackgroundJobTransactionSerializationOptions
|
|
@@ -1096,6 +1103,81 @@ export default class BackgroundJobsStore extends BackgroundJobsAdapter {
|
|
|
1096
1103
|
return handoffs
|
|
1097
1104
|
}
|
|
1098
1105
|
|
|
1106
|
+
/**
|
|
1107
|
+
* Snapshots exact, lease-aware active handoffs before a new main generation
|
|
1108
|
+
* starts accepting worker reconnects. Legacy rows without a complete worker,
|
|
1109
|
+
* lease, and timestamp identity stay owned by the age-based orphan sweep.
|
|
1110
|
+
* @returns {Promise<import("./types.js").BackgroundJobHandoffSnapshot[]>} - Exact startup handoffs.
|
|
1111
|
+
*/
|
|
1112
|
+
async snapshotHandedOffJobs() {
|
|
1113
|
+
await this.ensureReady()
|
|
1114
|
+
|
|
1115
|
+
const rows = await this._withDb(async (db) => await db
|
|
1116
|
+
.newQuery()
|
|
1117
|
+
.from(JOBS_TABLE)
|
|
1118
|
+
.where({status: "handed_off"})
|
|
1119
|
+
.order("created_at_ms ASC")
|
|
1120
|
+
.order("id ASC")
|
|
1121
|
+
.results())
|
|
1122
|
+
/** @type {import("./types.js").BackgroundJobHandoffSnapshot[]} */
|
|
1123
|
+
const handoffs = []
|
|
1124
|
+
|
|
1125
|
+
for (const row of rows) {
|
|
1126
|
+
const job = this._normalizeJobRow(row)
|
|
1127
|
+
|
|
1128
|
+
if (!job.handoffId || !job.workerId || typeof job.handedOffAtMs !== "number") continue
|
|
1129
|
+
|
|
1130
|
+
handoffs.push({
|
|
1131
|
+
handedOffAtMs: job.handedOffAtMs,
|
|
1132
|
+
handoffId: job.handoffId,
|
|
1133
|
+
jobId: job.id,
|
|
1134
|
+
workerId: job.workerId
|
|
1135
|
+
})
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
return handoffs
|
|
1139
|
+
}
|
|
1140
|
+
|
|
1141
|
+
/**
|
|
1142
|
+
* Reclaims only unchanged exact handoffs selected by a main-generation startup
|
|
1143
|
+
* snapshot. The ordinary orphan failure path owns retries, terminal status,
|
|
1144
|
+
* count transitions, schedule ownership, and concurrency release.
|
|
1145
|
+
* @param {object} args - Options.
|
|
1146
|
+
* @param {import("./types.js").BackgroundJobHandoffSnapshot[]} args.handoffs - Exact startup snapshots.
|
|
1147
|
+
* @param {ReturnType<typeof JSON.parse>} args.error - Orphan reason.
|
|
1148
|
+
* @returns {Promise<import("./types.js").BackgroundJobRow[]>} - Accepted transitions.
|
|
1149
|
+
*/
|
|
1150
|
+
async markOrphanedHandoffs({handoffs, error}) {
|
|
1151
|
+
await this.ensureReady()
|
|
1152
|
+
|
|
1153
|
+
return await this._serializedCountMutation(async (db) => {
|
|
1154
|
+
/** @type {BackgroundJobOrphanSelection[]} */
|
|
1155
|
+
const selections = []
|
|
1156
|
+
|
|
1157
|
+
for (const handoff of handoffs) {
|
|
1158
|
+
const job = await this._getJobRowById(db, handoff.jobId)
|
|
1159
|
+
|
|
1160
|
+
if (!job || job.status !== "handed_off") continue
|
|
1161
|
+
if (job.handoffId !== handoff.handoffId) continue
|
|
1162
|
+
if (job.workerId !== handoff.workerId) continue
|
|
1163
|
+
if (job.handedOffAtMs !== handoff.handedOffAtMs) continue
|
|
1164
|
+
|
|
1165
|
+
selections.push({
|
|
1166
|
+
conditions: {
|
|
1167
|
+
handed_off_at_ms: handoff.handedOffAtMs,
|
|
1168
|
+
handoff_id: handoff.handoffId,
|
|
1169
|
+
id: handoff.jobId,
|
|
1170
|
+
status: "handed_off",
|
|
1171
|
+
worker_id: handoff.workerId
|
|
1172
|
+
},
|
|
1173
|
+
job
|
|
1174
|
+
})
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1177
|
+
return await this._markOrphanSelections({db, error, selections})
|
|
1178
|
+
})
|
|
1179
|
+
}
|
|
1180
|
+
|
|
1099
1181
|
/**
|
|
1100
1182
|
* Runs mark failed.
|
|
1101
1183
|
* @param {object} args - Options.
|
|
@@ -1141,8 +1223,8 @@ export default class BackgroundJobsStore extends BackgroundJobsAdapter {
|
|
|
1141
1223
|
|
|
1142
1224
|
const rows = await query.results()
|
|
1143
1225
|
|
|
1144
|
-
/** @type {
|
|
1145
|
-
const
|
|
1226
|
+
/** @type {BackgroundJobOrphanSelection[]} */
|
|
1227
|
+
const selections = []
|
|
1146
1228
|
|
|
1147
1229
|
for (const row of rows) {
|
|
1148
1230
|
const job = this._normalizeJobRow(row)
|
|
@@ -1160,28 +1242,55 @@ export default class BackgroundJobsStore extends BackgroundJobsAdapter {
|
|
|
1160
1242
|
// wrongly release the concurrency reservation of — that new lease.
|
|
1161
1243
|
// `handed_off_at_ms` is always set on a handed-off row (and the SELECT
|
|
1162
1244
|
// required it `<= cutoff`), so it is a reliable null-safe lease pin.
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
job
|
|
1166
|
-
error: "Job orphaned after timeout",
|
|
1167
|
-
markOrphaned: true,
|
|
1168
|
-
conditions: {id: job.id, status: "handed_off", handed_off_at_ms: job.handedOffAtMs}
|
|
1245
|
+
selections.push({
|
|
1246
|
+
conditions: {id: job.id, status: "handed_off", handed_off_at_ms: job.handedOffAtMs},
|
|
1247
|
+
job
|
|
1169
1248
|
})
|
|
1170
|
-
|
|
1171
|
-
if (orphanedJob) orphanedJobs.push(orphanedJob)
|
|
1172
1249
|
}
|
|
1173
1250
|
|
|
1174
|
-
|
|
1175
|
-
|
|
1251
|
+
return await this._markOrphanSelections({
|
|
1252
|
+
db,
|
|
1253
|
+
error: "Job orphaned after timeout",
|
|
1254
|
+
selections
|
|
1255
|
+
})
|
|
1256
|
+
})
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1259
|
+
/**
|
|
1260
|
+
* Applies the common fenced orphan transition and records one aggregate count
|
|
1261
|
+
* delta for the accepted rows.
|
|
1262
|
+
* @param {object} args - Options.
|
|
1263
|
+
* @param {import("../database/drivers/base.js").default} args.db - Transaction connection.
|
|
1264
|
+
* @param {ReturnType<typeof JSON.parse>} args.error - Orphan reason.
|
|
1265
|
+
* @param {BackgroundJobOrphanSelection[]} args.selections - Selected handoffs and exact fences.
|
|
1266
|
+
* @returns {Promise<import("./types.js").BackgroundJobRow[]>} - Accepted transitions.
|
|
1267
|
+
*/
|
|
1268
|
+
async _markOrphanSelections({db, error, selections}) {
|
|
1269
|
+
/** @type {import("./types.js").BackgroundJobRow[]} */
|
|
1270
|
+
const orphanedJobs = []
|
|
1271
|
+
|
|
1272
|
+
for (const {conditions, job} of selections) {
|
|
1273
|
+
const orphanedJob = await this._applyFailure({
|
|
1274
|
+
conditions,
|
|
1275
|
+
db,
|
|
1276
|
+
error,
|
|
1277
|
+
job,
|
|
1278
|
+
markOrphaned: true
|
|
1279
|
+
})
|
|
1176
1280
|
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
deltas[status] += count
|
|
1180
|
-
}
|
|
1181
|
-
await this._recordCountDelta(db, deltas)
|
|
1281
|
+
if (orphanedJob) orphanedJobs.push(orphanedJob)
|
|
1282
|
+
}
|
|
1182
1283
|
|
|
1183
|
-
|
|
1184
|
-
|
|
1284
|
+
const statusCounts = this._statusCounts(orphanedJobs)
|
|
1285
|
+
const deltas = this._emptyCountBuckets()
|
|
1286
|
+
|
|
1287
|
+
for (const [status, count] of Object.entries(statusCounts)) {
|
|
1288
|
+
deltas.handed_off -= count
|
|
1289
|
+
deltas[status] += count
|
|
1290
|
+
}
|
|
1291
|
+
await this._recordCountDelta(db, deltas)
|
|
1292
|
+
|
|
1293
|
+
return orphanedJobs
|
|
1185
1294
|
}
|
|
1186
1295
|
|
|
1187
1296
|
/**
|
|
@@ -43,6 +43,13 @@
|
|
|
43
43
|
* @property {string} handoffId - Unique handoff lease id.
|
|
44
44
|
* @property {number} handedOffAtMs - Time handed to a worker in ms.
|
|
45
45
|
*/
|
|
46
|
+
/**
|
|
47
|
+
* @typedef {object} BackgroundJobHandoffSnapshot
|
|
48
|
+
* @property {string} jobId - Job holding the lease.
|
|
49
|
+
* @property {string} handoffId - Exact durable lease id.
|
|
50
|
+
* @property {string} workerId - Stable worker id that received the lease.
|
|
51
|
+
* @property {number} handedOffAtMs - Time handed to the worker in ms.
|
|
52
|
+
*/
|
|
46
53
|
/**
|
|
47
54
|
* @typedef {object} BackgroundJobHandoffRequest
|
|
48
55
|
* @property {string} jobId - Job to claim.
|