velocious 1.0.614 → 1.0.615

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/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "velocious": "build/bin/velocious.js"
4
4
  },
5
5
  "name": "velocious",
6
- "version": "1.0.614",
6
+ "version": "1.0.615",
7
7
  "main": "build/index.js",
8
8
  "types": "build/index.d.ts",
9
9
  "files": [
@@ -46,6 +46,7 @@ import {
46
46
  const MIGRATIONS_TABLE = "velocious_internal_migrations"
47
47
  const MIGRATION_SCOPE = "background_jobs"
48
48
  const MIGRATION_VERSION = "20250215000000"
49
+ const SCHEMA_RECOVERY_PENDING_VERSION = "schema-recovery-pending"
49
50
  const EXECUTION_MODE_BACKFILL_MIGRATION_VERSION = "20260607131010"
50
51
  // Drops the redundant legacy `forked` boolean column and rewrites pooled rows to
51
52
  // persist `execution_mode = "pooled"` directly (retiring the pooled-as-forked
@@ -186,6 +187,13 @@ export default class BackgroundJobsStore extends BackgroundJobsAdapter {
186
187
  async reconcileQueueConcurrency() {
187
188
  if (this._queueConcurrencyReconciled) return
188
189
 
190
+ const databaseIdentifier = this.getDatabaseIdentifier()
191
+ const startedAtMs = Date.now()
192
+
193
+ await this.logger.info(() => [
194
+ "Starting background jobs queue-concurrency startup reconciliation",
195
+ {databaseIdentifier}
196
+ ])
189
197
  await this.ensureReady()
190
198
 
191
199
  await this._withDb(async (db) => {
@@ -206,6 +214,11 @@ export default class BackgroundJobsStore extends BackgroundJobsAdapter {
206
214
  await db.releaseAdvisoryLock(lockName)
207
215
  }
208
216
  })
217
+
218
+ await this.logger.info(() => [
219
+ "Completed background jobs queue-concurrency startup reconciliation",
220
+ {databaseIdentifier, durationMs: Date.now() - startedAtMs}
221
+ ])
209
222
  }
210
223
 
211
224
  /**
@@ -1514,24 +1527,29 @@ export default class BackgroundJobsStore extends BackgroundJobsAdapter {
1514
1527
  await this._ensureMigrationsTable(db)
1515
1528
 
1516
1529
  const alreadyApplied = await this._hasMigration(db)
1530
+ const schemaRecoveryPending = await this._hasMigration(db, SCHEMA_RECOVERY_PENDING_VERSION)
1531
+ const jobsTableExists = await db.tableExists(JOBS_TABLE)
1517
1532
 
1518
1533
  // Even when the migration row is present, the jobs table itself can have
1519
1534
  // been dropped underneath us by a transaction rollback in another caller
1520
1535
  // (DDL is transactional on SQLite/MSSQL). Verify the table physically
1521
1536
  // exists and recreate it when missing rather than trusting the migration
1522
1537
  // row alone, otherwise later callers fail with "no such table".
1523
- if (alreadyApplied && await db.tableExists(JOBS_TABLE)) {
1538
+ if (alreadyApplied && jobsTableExists && !schemaRecoveryPending) {
1524
1539
  await this._ensureJobsTableColumns(db)
1525
1540
  await this._ensureIdempotencyKeysTable(db)
1526
1541
  await this._ensureMailDeliveryOperationsTable(db)
1527
1542
  await this._ensureScheduleKeysTable(db)
1528
1543
  await this._ensureConcurrencyTable(db)
1529
1544
  await this._ensureCountRevisionTable(db)
1530
- await this._reconcileConcurrency(db)
1531
1545
 
1532
1546
  return
1533
1547
  }
1534
1548
 
1549
+ if (alreadyApplied && !schemaRecoveryPending) {
1550
+ await this._recordMigration(db, SCHEMA_RECOVERY_PENDING_VERSION)
1551
+ }
1552
+
1535
1553
  await this._applyMigrations(db)
1536
1554
  await this._ensureJobsTableColumns(db)
1537
1555
  await this._ensureIdempotencyKeysTable(db)
@@ -1539,9 +1557,18 @@ export default class BackgroundJobsStore extends BackgroundJobsAdapter {
1539
1557
  await this._ensureScheduleKeysTable(db)
1540
1558
  await this._ensureConcurrencyTable(db)
1541
1559
  await this._ensureCountRevisionTable(db)
1542
- await this._reconcileConcurrency(db)
1543
1560
 
1544
- if (alreadyApplied) return
1561
+ if (alreadyApplied) {
1562
+ // The recreated jobs table is empty, but the surviving concurrency table
1563
+ // can still count handoffs that disappeared with the dropped jobs table.
1564
+ await this._reconcileConcurrency(db)
1565
+ await db.delete({
1566
+ tableName: MIGRATIONS_TABLE,
1567
+ conditions: {key: this._migrationKey(SCHEMA_RECOVERY_PENDING_VERSION)}
1568
+ })
1569
+
1570
+ return
1571
+ }
1545
1572
 
1546
1573
  await this._recordMigration(db, MIGRATION_VERSION)
1547
1574
  }
@@ -2578,7 +2605,7 @@ export default class BackgroundJobsStore extends BackgroundJobsAdapter {
2578
2605
  }
2579
2606
 
2580
2607
  /**
2581
- * Rebuilds durable counts from active handoffs after startup.
2608
+ * Rebuilds durable counts from active handoffs.
2582
2609
  * @param {import("../database/drivers/base.js").default} db - Database connection.
2583
2610
  * @returns {Promise<void>} - Resolves when reconciled.
2584
2611
  */