Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
8035964e1This file is pinned to the selected release. Download the original to open it in your design tool.
import 'dotenv/config'
import { closeBus } from './lib/bus.js'
import { backfillMachineFreeEntitlements } from './lib/db/freeEntitlement.js'
import {
backfillMachineAuthMode,
backfillMachinePresenceTurnsStarted,
ensureSchema,
migrateAutonomousEnvironment,
migrateMachineRename,
migrateUserIdentityByEmail,
migrateUserPresencePerMachine,
pruneLegacyDeviceBindings,
} from './lib/db/migrate.js'
import { ensurePlans } from './lib/db/seed.js'
import { prisma } from './lib/prisma.js'
import { machineBillingWorkerService } from './services/MachineBillingWorkerService.js'
import { logger } from './utils/logger.js'
// Singleton background process. HTTP/WS server.ts runs as a PM2 cluster and must never own schema
// writes, catalog syncs, migrations or periodic jobs; otherwise every live server worker races them.
async function start(): Promise<void> {
// Existing production data was created against staging upstreams. Stamp it before Prisma swaps
// the old global unique indexes for their per-environment replacements.
await migrateAutonomousEnvironment()
await migrateUserIdentityByEmail()
// Same reason: the old (user, day) unique must be gone before the push installs its replacement.
await migrateUserPresencePerMachine()
ensureSchema()
// AFTER the push: it creates the new collections + their unique indexes, and the copy uses $merge
// so those indexes survive. Copying first would leave the unique index build to fail silently.
await migrateMachineRename()
// The copy can materialize rows from a collection the first pass never saw — stamp those too.
await migrateAutonomousEnvironment()
await ensurePlans()
await backfillMachineAuthMode()
await pruneLegacyDeviceBindings()
await backfillMachineFreeEntitlements()
await backfillMachinePresenceTurnsStarted()
const shutdown = (signal: string): void => {
logger.info(`Received ${signal}, stopping backend worker...`)
const hardExit = setTimeout(() => process.exit(0), 5000)
hardExit.unref()
machineBillingWorkerService.stop()
void Promise.allSettled([prisma.$disconnect(), closeBus()]).finally(() => process.exit(0))
}
process.on('SIGINT', () => shutdown('SIGINT'))
process.on('SIGTERM', () => shutdown('SIGTERM'))
machineBillingWorkerService.start()
// PM2 wait_ready gates the singleton worker's "online" state on schema/catalog/backfill startup.
// Plain node/tsx runs do not provide process.send and simply continue.
process.send?.('ready')
logger.info('backend worker started')
}
start().catch((err) => {
logger.error('Failed to start backend worker', err)
process.exit(1)
})