Mirror of https://github.com/roostorg/coop
github.com/roostorg/coop
1#!/usr/bin/env node
2import _ from 'lodash';
3
4import getBottle from '../iocContainer/index.js';
5import { logErrorJson } from '../utils/logging.js';
6import { type WorkerOrJob } from '../workers_jobs/index.js';
7
8const { container } = await getBottle();
9
10const workerOrJobName = process.argv[2];
11const workerOrJob = (container as any)[workerOrJobName] as WorkerOrJob;
12const controller = new AbortController();
13
14// When the worker/job finishes naturally (which only applies to jobs, as
15// workers are meant to run forever), or when it throws an error, or when it
16// gets shutdown by kubernetes, we run this function to cleanup gracefully.
17// We call shutdown here, rather than in an `abort` listener on the signal so
18// that we can await shutdown() finishing.
19const onFinish = _.once((errorWhileRunningJobOrWorker?: Error) => {
20 let exitWithFailure = Boolean(errorWhileRunningJobOrWorker);
21
22 if (errorWhileRunningJobOrWorker) {
23 // eslint-disable-next-line no-restricted-syntax
24 logErrorJson({
25 message: 'shutdown worker/job after encountering error during run',
26 error: errorWhileRunningJobOrWorker,
27 });
28 }
29
30 try {
31 controller.abort();
32 } catch (e) {
33 exitWithFailure = true;
34 // eslint-disable-next-line no-restricted-syntax
35 logErrorJson({
36 message: 'graceful shutdown failed while running abort signal listeners',
37 error: e,
38 });
39 }
40
41 workerOrJob.shutdown().then(
42 () => {
43 process.exit(exitWithFailure ? 1 : 0);
44 },
45 (e) => {
46 // eslint-disable-next-line no-restricted-syntax
47 logErrorJson({
48 message: 'graceful shutdown failed with error',
49 error: e,
50 });
51 process.exit(1);
52 },
53 );
54});
55
56workerOrJob.run(controller.signal).then(
57 // For jobs -- but not workers --- shut down when run()'s returned promise
58 // is settled. Workers, meanwhile, only shut down if there's actually an error.
59 workerOrJob.type === 'Job' ? () => onFinish() : () => {},
60 onFinish,
61);
62
63process.on('uncaughtException', (err, _) => {
64 // eslint-disable-next-line no-restricted-syntax
65 logErrorJson({
66 message: 'UncaughtException',
67 error: err,
68 });
69 process.exit(1);
70});
71
72process.once('SIGTERM', onFinish);
73process.once('SIGINT', onFinish);