From 7cf3c57c618ce8f3ae47571724fe6d087418fa5e Mon Sep 17 00:00:00 2001 From: simon Date: Fri, 9 Dec 2022 13:51:38 +0100 Subject: [PATCH] fix: add error message to forked child and give it a chance to die --- README.md | 26 ++++-- package-lock.json | 136 ++++++++++++++--------------- package.json | 16 ++-- src/Job.ts | 11 ++- src/index.ts | 7 +- test/fixtures/someJobDefinition.ts | 7 +- test/helpers/forkHelper.ts | 26 ++++-- test/job.test.ts | 44 ++++++++++ 8 files changed, 174 insertions(+), 99 deletions(-) diff --git a/README.md b/README.md index b3b72df..f21e57d 100644 --- a/README.md +++ b/README.md @@ -1148,13 +1148,9 @@ childWorker.ts ```ts import 'reflect-metadata'; -process.on('message', message => { - if (message === 'cancel') { - process.exit(2); - } else { - console.log('got message', message); - } -}); +function isCancelMessage(message): message is { type: 'cancel'; error: string } { + return message !== null && typeof message === 'object' && message.type === 'cancel'; +} (async () => { const mongooseConnection = /** connect to database */ @@ -1200,7 +1196,21 @@ process.on('message', message => { } // run this job now - await agenda.runForkedJob(jobId); + const job = await agenda.getForkedJob(jobId); + + process.on('message', message => { + if (isCancelMessage(message)) { + job.cancel(message.error); + setTimeout(() => { + // kill it after 10 seconds + process.exit(2); + }, 10000); + } else { + console.log('got message', message); + } + }); + + await job.runJob(); // disconnect database and exit process.exit(0); diff --git a/package-lock.json b/package-lock.json index d0df958..1f56083 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,27 +17,27 @@ "mongodb": "^4" }, "devDependencies": { - "@hokify/eslint-config": "^2.3.6", + "@hokify/eslint-config": "^2.3.8", "@istanbuljs/nyc-config-typescript": "^1.0.2", "@types/chai": "^4.3.4", "@types/debug": "^4.1.7", "@types/human-interval": "^1.0.0", "@types/luxon": "^3.1.0", - "@types/mocha": "^10.0.0", - "@types/node": "^18.11.9", + "@types/mocha": "^10.0.1", + "@types/node": "^18.11.12", "@types/sinon": "^10.0.13", "chai": "^4.3.7", "delay": "5.0.0", - "eslint": "^8.27.0", + "eslint": "^8.29.0", "mocha": "10.1.0", - "mongodb-memory-server": "^8.10.0", + "mongodb-memory-server": "^8.10.1", "nyc": "^15.1.0", - "prettier": "^2.7.1", - "sinon": "14.0.2", + "prettier": "^2.8.1", + "sinon": "15.0.0", "standard-version": "^9.5.0", "ts-node": "^10.9.1", "typedoc": "^0.23.21", - "typescript": "^4.9.3" + "typescript": "^4.9.4" }, "engines": { "node": ">=14.0.0" @@ -1570,13 +1570,13 @@ } }, "node_modules/@hokify/eslint-config": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/@hokify/eslint-config/-/eslint-config-2.3.6.tgz", - "integrity": "sha512-LQD2FLPir/CvPS6ErEh1/pTSUdqwzQkkct2uuGhh5ty+6K05qVXjQ3e/e6oWs42VHSbLx5kJS2nGVtg/fuJIKg==", + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/@hokify/eslint-config/-/eslint-config-2.3.8.tgz", + "integrity": "sha512-Q5TDtalK1+QJQ8Evc+3VDV4Z5kH9+E+cbUTAHKCYkrjfUBUGqx6XrbFQ/TFjt469kBYhJynwZwR1iOObAg64cA==", "dev": true, "dependencies": { - "@typescript-eslint/eslint-plugin": "^5.40.1", - "@typescript-eslint/parser": "^5.40.1", + "@typescript-eslint/eslint-plugin": "^5.43.0", + "@typescript-eslint/parser": "^5.43.0", "eslint-config-airbnb-base": "^15.0.0", "eslint-config-airbnb-typescript": "^17.0.0", "eslint-config-prettier": "^8.5.0", @@ -1941,9 +1941,9 @@ "dev": true }, "node_modules/@types/mocha": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.0.tgz", - "integrity": "sha512-rADY+HtTOA52l9VZWtgQfn4p+UDVM2eDVkMZT1I6syp0YKxW2F9v+0pbRZLsvskhQv/vMb6ZfCay81GHbz5SHg==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.1.tgz", + "integrity": "sha512-/fvYntiO1GeICvqbQ3doGDIP97vWmvFt83GKguJ6prmQM2iXZfFcq6YE8KteFyRtX2/h5Hf91BYvPodJKFYv5Q==", "dev": true }, "node_modules/@types/ms": { @@ -1953,9 +1953,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "18.11.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.9.tgz", - "integrity": "sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==" + "version": "18.11.12", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.12.tgz", + "integrity": "sha512-FgD3NtTAKvyMmD44T07zz2fEf+OKwutgBCEVM8GcvMGVGaDktiLNTDvPwC/LUe3PinMW+X6CuLOF2Ui1mAlSXg==" }, "node_modules/@types/normalize-package-data": { "version": "2.4.1", @@ -3769,9 +3769,9 @@ } }, "node_modules/eslint": { - "version": "8.27.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.27.0.tgz", - "integrity": "sha512-0y1bfG2ho7mty+SiILVf9PfuRA49ek4Nc60Wmmu62QlobNR+CeXa4xXIJgcuwSQgZiWaPH+5BDsctpIW0PR/wQ==", + "version": "8.29.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.29.0.tgz", + "integrity": "sha512-isQ4EEiyUjZFbEKvEGJKKGBwXtvXX+zJbkVKCgTuB9t/+jUBcy8avhkEwWJecI15BkRkOYmvIM5ynbhRjEkoeg==", "dev": true, "dependencies": { "@eslint/eslintrc": "^1.3.3", @@ -6554,13 +6554,13 @@ } }, "node_modules/mongodb-memory-server": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/mongodb-memory-server/-/mongodb-memory-server-8.10.0.tgz", - "integrity": "sha512-LCYIrbzwRZlkDt2OM3gyS7458z68Zf3EdKrcnB0lknOypdWExfhBLUURjfhHCNs+FglDiqLn3uwEUi6Xmye6Fw==", + "version": "8.10.1", + "resolved": "https://registry.npmjs.org/mongodb-memory-server/-/mongodb-memory-server-8.10.1.tgz", + "integrity": "sha512-xBo45TuU4SFjDWixOXJyTBDukYqGeCuh7RBcDm4Nqngd/2Pjja/XYYFFJk/I44mTrZ77W1HDmCA4d69XgNJUJQ==", "dev": true, "hasInstallScript": true, "dependencies": { - "mongodb-memory-server-core": "8.10.0", + "mongodb-memory-server-core": "8.10.1", "tslib": "^2.4.1" }, "engines": { @@ -6568,9 +6568,9 @@ } }, "node_modules/mongodb-memory-server-core": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/mongodb-memory-server-core/-/mongodb-memory-server-core-8.10.0.tgz", - "integrity": "sha512-otLYpVARSBXh1zaMRHet2MiUi+rl7rUQe9eXxDAPunC70ZhoGjxIvbQOsVA+n6o09UlxbupWjE4pUu8Ezq7zYQ==", + "version": "8.10.1", + "resolved": "https://registry.npmjs.org/mongodb-memory-server-core/-/mongodb-memory-server-core-8.10.1.tgz", + "integrity": "sha512-Xva73v08VDojH1+423fJA6PWsoSWnkexk8/zSCdQTfKXACAgEaQ5fay89gzYn/bn/4So89hPVdLwEOt2VYMK7Q==", "dev": true, "dependencies": { "@types/tmp": "^0.2.3", @@ -7336,9 +7336,9 @@ } }, "node_modules/prettier": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz", - "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.1.tgz", + "integrity": "sha512-lqGoSJBQNJidqCHE80vqZJHWHRFoNYsSpP9AjFhlhi9ODCJA541svILes/+/1GM3VaL/abZi7cpFzOpdR9UPKg==", "dev": true, "bin": { "prettier": "bin-prettier.js" @@ -7887,9 +7887,9 @@ "dev": true }, "node_modules/sinon": { - "version": "14.0.2", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-14.0.2.tgz", - "integrity": "sha512-PDpV0ZI3ZCS3pEqx0vpNp6kzPhHrLx72wA0G+ZLaaJjLIYeE0n8INlgaohKuGy7hP0as5tbUd23QWu5U233t+w==", + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-15.0.0.tgz", + "integrity": "sha512-pV97G1GbslaSJoSdy2F2z8uh5F+uPGp3ddOzA4JsBOUBLEQRz2OAqlKGRFTSh2KiqUCmHkzyAeu7R4x1Hx0wwg==", "dev": true, "dependencies": { "@sinonjs/commons": "^2.0.0", @@ -8691,9 +8691,9 @@ } }, "node_modules/typescript": { - "version": "4.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.3.tgz", - "integrity": "sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==", + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", + "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -10278,13 +10278,13 @@ } }, "@hokify/eslint-config": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/@hokify/eslint-config/-/eslint-config-2.3.6.tgz", - "integrity": "sha512-LQD2FLPir/CvPS6ErEh1/pTSUdqwzQkkct2uuGhh5ty+6K05qVXjQ3e/e6oWs42VHSbLx5kJS2nGVtg/fuJIKg==", + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/@hokify/eslint-config/-/eslint-config-2.3.8.tgz", + "integrity": "sha512-Q5TDtalK1+QJQ8Evc+3VDV4Z5kH9+E+cbUTAHKCYkrjfUBUGqx6XrbFQ/TFjt469kBYhJynwZwR1iOObAg64cA==", "dev": true, "requires": { - "@typescript-eslint/eslint-plugin": "^5.40.1", - "@typescript-eslint/parser": "^5.40.1", + "@typescript-eslint/eslint-plugin": "^5.43.0", + "@typescript-eslint/parser": "^5.43.0", "eslint-config-airbnb-base": "^15.0.0", "eslint-config-airbnb-typescript": "^17.0.0", "eslint-config-prettier": "^8.5.0", @@ -10585,9 +10585,9 @@ "dev": true }, "@types/mocha": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.0.tgz", - "integrity": "sha512-rADY+HtTOA52l9VZWtgQfn4p+UDVM2eDVkMZT1I6syp0YKxW2F9v+0pbRZLsvskhQv/vMb6ZfCay81GHbz5SHg==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.1.tgz", + "integrity": "sha512-/fvYntiO1GeICvqbQ3doGDIP97vWmvFt83GKguJ6prmQM2iXZfFcq6YE8KteFyRtX2/h5Hf91BYvPodJKFYv5Q==", "dev": true }, "@types/ms": { @@ -10597,9 +10597,9 @@ "dev": true }, "@types/node": { - "version": "18.11.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.9.tgz", - "integrity": "sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==" + "version": "18.11.12", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.12.tgz", + "integrity": "sha512-FgD3NtTAKvyMmD44T07zz2fEf+OKwutgBCEVM8GcvMGVGaDktiLNTDvPwC/LUe3PinMW+X6CuLOF2Ui1mAlSXg==" }, "@types/normalize-package-data": { "version": "2.4.1", @@ -11939,9 +11939,9 @@ "dev": true }, "eslint": { - "version": "8.27.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.27.0.tgz", - "integrity": "sha512-0y1bfG2ho7mty+SiILVf9PfuRA49ek4Nc60Wmmu62QlobNR+CeXa4xXIJgcuwSQgZiWaPH+5BDsctpIW0PR/wQ==", + "version": "8.29.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.29.0.tgz", + "integrity": "sha512-isQ4EEiyUjZFbEKvEGJKKGBwXtvXX+zJbkVKCgTuB9t/+jUBcy8avhkEwWJecI15BkRkOYmvIM5ynbhRjEkoeg==", "dev": true, "requires": { "@eslint/eslintrc": "^1.3.3", @@ -13990,19 +13990,19 @@ } }, "mongodb-memory-server": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/mongodb-memory-server/-/mongodb-memory-server-8.10.0.tgz", - "integrity": "sha512-LCYIrbzwRZlkDt2OM3gyS7458z68Zf3EdKrcnB0lknOypdWExfhBLUURjfhHCNs+FglDiqLn3uwEUi6Xmye6Fw==", + "version": "8.10.1", + "resolved": "https://registry.npmjs.org/mongodb-memory-server/-/mongodb-memory-server-8.10.1.tgz", + "integrity": "sha512-xBo45TuU4SFjDWixOXJyTBDukYqGeCuh7RBcDm4Nqngd/2Pjja/XYYFFJk/I44mTrZ77W1HDmCA4d69XgNJUJQ==", "dev": true, "requires": { - "mongodb-memory-server-core": "8.10.0", + "mongodb-memory-server-core": "8.10.1", "tslib": "^2.4.1" } }, "mongodb-memory-server-core": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/mongodb-memory-server-core/-/mongodb-memory-server-core-8.10.0.tgz", - "integrity": "sha512-otLYpVARSBXh1zaMRHet2MiUi+rl7rUQe9eXxDAPunC70ZhoGjxIvbQOsVA+n6o09UlxbupWjE4pUu8Ezq7zYQ==", + "version": "8.10.1", + "resolved": "https://registry.npmjs.org/mongodb-memory-server-core/-/mongodb-memory-server-core-8.10.1.tgz", + "integrity": "sha512-Xva73v08VDojH1+423fJA6PWsoSWnkexk8/zSCdQTfKXACAgEaQ5fay89gzYn/bn/4So89hPVdLwEOt2VYMK7Q==", "dev": true, "requires": { "@types/tmp": "^0.2.3", @@ -14601,9 +14601,9 @@ "dev": true }, "prettier": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz", - "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.1.tgz", + "integrity": "sha512-lqGoSJBQNJidqCHE80vqZJHWHRFoNYsSpP9AjFhlhi9ODCJA541svILes/+/1GM3VaL/abZi7cpFzOpdR9UPKg==", "dev": true }, "prettier-linter-helpers": { @@ -14997,9 +14997,9 @@ "dev": true }, "sinon": { - "version": "14.0.2", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-14.0.2.tgz", - "integrity": "sha512-PDpV0ZI3ZCS3pEqx0vpNp6kzPhHrLx72wA0G+ZLaaJjLIYeE0n8INlgaohKuGy7hP0as5tbUd23QWu5U233t+w==", + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-15.0.0.tgz", + "integrity": "sha512-pV97G1GbslaSJoSdy2F2z8uh5F+uPGp3ddOzA4JsBOUBLEQRz2OAqlKGRFTSh2KiqUCmHkzyAeu7R4x1Hx0wwg==", "dev": true, "requires": { "@sinonjs/commons": "^2.0.0", @@ -15608,9 +15608,9 @@ } }, "typescript": { - "version": "4.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.3.tgz", - "integrity": "sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==", + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", + "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==", "dev": true }, "uglify-js": { diff --git a/package.json b/package.json index 87507a7..6cb04e3 100644 --- a/package.json +++ b/package.json @@ -59,26 +59,26 @@ "mongodb": "^4" }, "devDependencies": { - "eslint": "^8.27.0", - "prettier": "^2.7.1", - "@hokify/eslint-config": "^2.3.6", + "eslint": "^8.29.0", + "prettier": "^2.8.1", + "@hokify/eslint-config": "^2.3.8", "@istanbuljs/nyc-config-typescript": "^1.0.2", "@types/chai": "^4.3.4", "@types/debug": "^4.1.7", "@types/human-interval": "^1.0.0", "@types/luxon": "^3.1.0", - "@types/mocha": "^10.0.0", - "@types/node": "^18.11.9", + "@types/mocha": "^10.0.1", + "@types/node": "^18.11.12", "@types/sinon": "^10.0.13", "chai": "^4.3.7", "delay": "5.0.0", "mocha": "10.1.0", - "mongodb-memory-server": "^8.10.0", + "mongodb-memory-server": "^8.10.1", "nyc": "^15.1.0", - "sinon": "14.0.2", + "sinon": "15.0.0", "standard-version": "^9.5.0", "ts-node": "^10.9.1", "typedoc": "^0.23.21", - "typescript": "^4.9.3" + "typescript": "^4.9.4" } } diff --git a/src/Job.ts b/src/Job.ts index 1fd2a3b..ed1eda8 100644 --- a/src/Job.ts +++ b/src/Job.ts @@ -20,7 +20,7 @@ export class Job { * you can use it for long running tasks to periodically check if canceled is true, * also touch will check if and throws that the job got canceled */ - private canceled?: Error | true; + private canceled?: Error | string | true; getCanceledMessage() { return typeof this.canceled === 'object' @@ -30,14 +30,17 @@ export class Job { private forkedChild?: ChildProcess; - cancel(error?: Error) { + cancel(error?: Error | string) { this.agenda.emit(`cancel:${this.attrs.name}`, this); this.canceled = error || true; if (this.forkedChild) { try { - this.forkedChild.send('cancel'); + this.forkedChild.send({ + type: 'cancel', + error: this.canceled instanceof Error ? this.canceled.message : this.canceled + }); // eslint-disable-next-line no-console - console.info('canceled child', this.attrs.name, this.attrs._id); + console.info('send canceled child', this.attrs.name, this.attrs._id); } catch (err) { // eslint-disable-next-line no-console console.log('cannot send cancel to child'); diff --git a/src/index.ts b/src/index.ts index 1b1e876..a2acb66 100644 --- a/src/index.ts +++ b/src/index.ts @@ -76,13 +76,13 @@ export class Agenda extends EventEmitter { return !!this.jobProcessor; } - async runForkedJob(jobId: string) { + async getForkedJob(jobId: string) { const jobData = await this.db.getJobById(jobId); if (!jobData) { throw new Error('db entry not found'); } const job = new Job(this, jobData); - await job.runJob(); + return job; } async getRunningStats(fullDetails = false): Promise { @@ -555,6 +555,9 @@ export class Agenda extends EventEmitter { const lockedJobs = this.jobProcessor.stop(); log('Agenda._unlockJobs()'); + + lockedJobs?.forEach(job => job.cancel(new Error('agenda stopped'))); + const jobIds = lockedJobs?.map(job => job.attrs._id) || []; if (jobIds.length > 0) { diff --git a/test/fixtures/someJobDefinition.ts b/test/fixtures/someJobDefinition.ts index 0acd9c3..68f836b 100644 --- a/test/fixtures/someJobDefinition.ts +++ b/test/fixtures/someJobDefinition.ts @@ -6,7 +6,12 @@ export default (agenda: Agenda, _definitionOnly = false) => { if (job.attrs.data?.failIt === 'error') { throw new Error('intended error :-)'); } else if (job.attrs.data?.failIt === 'die') { - process.exit(2); + process.exit(3); + } else if (job.attrs.data?.failIt === 'timeout') { + await new Promise(resolve => { + setTimeout(resolve, 5000); + }); } + await job.touch(); }); }; diff --git a/test/helpers/forkHelper.ts b/test/helpers/forkHelper.ts index 48f0c5f..5c85d59 100644 --- a/test/helpers/forkHelper.ts +++ b/test/helpers/forkHelper.ts @@ -1,12 +1,8 @@ import { Agenda } from '../../src'; -process.on('message', message => { - if (message === 'cancel') { - process.exit(2); - } else { - console.log('got message', message); - } -}); +function isCancelMessage(message): message is { type: 'cancel'; error: string } { + return message !== null && typeof message === 'object' && message.type === 'cancel'; +} (async () => { /** do other required initializations */ @@ -50,7 +46,21 @@ process.on('message', message => { } // run this job now - await agenda.runForkedJob(jobId); + const job = await agenda.getForkedJob(jobId); + + process.on('message', message => { + if (isCancelMessage(message)) { + job.cancel(message.error); + setTimeout(() => { + // kill it after 10 seconds + process.exit(2); + }, 10000); + } else { + console.log('got message', message); + } + }); + + await job.runJob(); // disconnect database and exit process.exit(0); diff --git a/test/job.test.ts b/test/job.test.ts index a680038..a9f1f6f 100644 --- a/test/job.test.ts +++ b/test/job.test.ts @@ -1785,5 +1785,49 @@ describe('Job', () => { expect(jobDataFinished?.failReason).to.not.be.eq(null); expect(jobDataFinished?.failCount).to.be.eq(1); }); + + it('runs a job in fork mode, but let it timeout', async () => { + const agendaFork = new Agenda({ + mongo: mongoDb, + forkHelper: { + path: './test/helpers/forkHelper.ts', + options: { + env: { DB_CONNECTION: mongoCfg }, + execArgv: ['-r', 'ts-node/register'] + } + }, + defaultLockLifetime: 1000 + }); + + expect(agendaFork.forkHelper?.path).to.be.eq('./test/helpers/forkHelper.ts'); + + const job = agendaFork.create('some job', { failIt: 'timeout' }); + job.forkMode(true); + job.schedule('now'); + await job.save(); + + const jobData = await agenda.db.getJobById(job.attrs._id as any); + + if (!jobData) { + throw new Error('job not found'); + } + + expect(jobData.fork).to.be.eq(true); + + // initialize job definition (keep in a seperate file to have a easier fork mode implementation) + someJobDefinition(agendaFork); + + await agendaFork.start(); + + do { + // console.log('.'); + await delay(50); + } while (await job.isRunning()); + + const jobDataFinished = await agenda.db.getJobById(job.attrs._id as any); + expect(jobDataFinished?.lastFinishedAt).to.not.be.eq(undefined); + expect(jobDataFinished?.failReason).to.not.be.eq(null); + expect(jobDataFinished?.failCount).to.be.eq(1); + }); }); });