* setup bskycard * quick proof of concept for png card generation * bskycard: use jsx * bskycard: 3x5 profile layout * bskycard: add butterfly overlay * bskycard: tidy * bskycard: separate and reorganize * bskycard: tidy * bskycard: tidy * bskycard: tidy * bskycard: poc of transparent overlay and box shadow * bskycard: reorg impl into src/ directory * bskycard: use more standard app structure * bskycard: setup dockerfile, fix build * bskycard: support for x-origin-verify * bskycard: card layout, filter images based on labels * bskycard: tidy * bskycard: support cluster mode * bskycard: handle error fetching starter pack info * bskycard: tidy * bskycard: fix leak on failed image fetch * bskycard: build workflow * bskyogcard: rename from bskycard * bskyogcard: fix some express plumbing * bskyogcard: add cdn tags, tidy
48 lines
1.3 KiB
TypeScript
48 lines
1.3 KiB
TypeScript
import cluster, {Worker} from 'node:cluster'
|
|
|
|
import {envInt} from '@atproto/common'
|
|
|
|
import {CardService, envToCfg, httpLogger, readEnv} from './index.js'
|
|
|
|
async function main() {
|
|
const env = readEnv()
|
|
const cfg = envToCfg(env)
|
|
const card = await CardService.create(cfg)
|
|
await card.start()
|
|
httpLogger.info('card service is running')
|
|
process.on('SIGTERM', async () => {
|
|
httpLogger.info('card service is stopping')
|
|
await card.destroy()
|
|
httpLogger.info('card service is stopped')
|
|
if (cluster.isWorker) process.exit(0)
|
|
})
|
|
}
|
|
|
|
const workerCount = envInt('CARD_CLUSTER_WORKER_COUNT')
|
|
|
|
if (workerCount) {
|
|
if (cluster.isPrimary) {
|
|
httpLogger.info(`primary ${process.pid} is running`)
|
|
const workers = new Set<Worker>()
|
|
for (let i = 0; i < workerCount; ++i) {
|
|
workers.add(cluster.fork())
|
|
}
|
|
let teardown = false
|
|
cluster.on('exit', worker => {
|
|
workers.delete(worker)
|
|
if (!teardown) {
|
|
workers.add(cluster.fork()) // restart on crash
|
|
}
|
|
})
|
|
process.on('SIGTERM', () => {
|
|
teardown = true
|
|
httpLogger.info('disconnecting workers')
|
|
workers.forEach(w => w.kill('SIGTERM'))
|
|
})
|
|
} else {
|
|
httpLogger.info(`worker ${process.pid} is running`)
|
|
main()
|
|
}
|
|
} else {
|
|
main() // non-clustering
|
|
}
|