1
1
import * as date from 'date.js' ;
2
2
import * as debug from 'debug' ;
3
3
import { ObjectId } from 'mongodb' ;
4
- import { fork } from 'child_process' ;
4
+ import { ChildProcess , fork } from 'child_process' ;
5
5
import type { Agenda } from './index' ;
6
6
import type { DefinitionProcessor } from './types/JobDefinition' ;
7
7
import { IJobParameters , datefields , TJobDatefield } from './types/JobParameters' ;
@@ -20,7 +20,27 @@ export class Job<DATA = unknown | void> {
20
20
* you can use it for long running tasks to periodically check if canceled is true,
21
21
* also touch will check if and throws that the job got canceled
22
22
*/
23
- canceled : Error | undefined ;
23
+ private canceled ?: Error | true ;
24
+
25
+ getCanceledMessage ( ) {
26
+ return typeof this . canceled === 'object'
27
+ ? this . canceled ?. message || this . canceled
28
+ : this . canceled ;
29
+ }
30
+
31
+ private forkedChild ?: ChildProcess ;
32
+
33
+ cancel ( error ?: Error ) {
34
+ this . canceled = error || true ;
35
+ if ( this . forkedChild ) {
36
+ try {
37
+ this . forkedChild . send ( 'cancel' ) ;
38
+ console . info ( 'canceled child' , this . attrs . name , this . attrs . _id ) ;
39
+ } catch ( err ) {
40
+ console . log ( 'cannot send cancel to child' ) ;
41
+ }
42
+ }
43
+ }
24
44
25
45
/** internal variable to ensure a job does not set unlimited numbers of setTimeouts if the job is not processed
26
46
* immediately */
@@ -266,12 +286,6 @@ export class Job<DATA = unknown | void> {
266
286
}
267
287
268
288
async isDead ( ) : Promise < boolean > {
269
- if ( ! this . byJobProcessor || this . attrs . fork ) {
270
- // we have no job definition, therfore we are not the job processor, but a client call
271
- // so we get the real state from database
272
- await this . fetchStatus ( ) ;
273
- }
274
-
275
289
return this . isExpired ( ) ;
276
290
}
277
291
@@ -360,68 +374,47 @@ export class Job<DATA = unknown | void> {
360
374
}
361
375
const { forkHelper } = this . agenda ;
362
376
363
- let stillRunning = true ;
364
- try {
365
- await new Promise < void > ( ( resolve , reject ) => {
366
- const child = fork (
367
- forkHelper . path ,
368
- [
377
+ await new Promise < void > ( ( resolve , reject ) => {
378
+ this . forkedChild = fork (
379
+ forkHelper . path ,
380
+ [
381
+ this . attrs . name ,
382
+ this . attrs . _id ! . toString ( ) ,
383
+ this . agenda . definitions [ this . attrs . name ] . filePath || ''
384
+ ] ,
385
+ forkHelper . options
386
+ ) ;
387
+
388
+ let childError : any ;
389
+ this . forkedChild . on ( 'close' , code => {
390
+ if ( code ) {
391
+ console . info (
392
+ 'fork parameters' ,
393
+ forkHelper ,
369
394
this . attrs . name ,
370
- this . attrs . _id ! . toString ( ) ,
371
- this . agenda . definitions [ this . attrs . name ] . filePath || ''
372
- ] ,
373
- forkHelper . options
374
- ) ;
375
-
376
- child . on ( 'close' , code => {
377
- stillRunning = false ;
378
- if ( code ) {
379
- console . info (
380
- 'fork parameters' ,
381
- forkHelper ,
382
- this . attrs . name ,
383
- this . attrs . _id ,
384
- this . agenda . definitions [ this . attrs . name ] . filePath
385
- ) ;
386
- const error = new Error ( `child process exited with code: ${ code } ` ) ;
387
- console . warn ( error . message ) ;
388
- reject ( error ) ;
389
- } else {
390
- resolve ( ) ;
391
- }
392
- } ) ;
393
- child . on ( 'message' , message => {
394
- // console.log(`Message from child.js: ${message}`, JSON.stringify(message));
395
- if ( typeof message === 'string' ) {
396
- try {
397
- reject ( JSON . parse ( message ) ) ;
398
- } catch ( errJson ) {
399
- reject ( message ) ;
400
- }
401
- } else {
402
- reject ( message ) ;
395
+ this . attrs . _id ,
396
+ this . agenda . definitions [ this . attrs . name ] . filePath
397
+ ) ;
398
+ const error = new Error ( `child process exited with code: ${ code } ` ) ;
399
+ console . warn ( error . message ) ;
400
+ reject ( childError || error ) ;
401
+ } else {
402
+ resolve ( ) ;
403
+ }
404
+ } ) ;
405
+ this . forkedChild . on ( 'message' , message => {
406
+ // console.log(`Message from child.js: ${message}`, JSON.stringify(message));
407
+ if ( typeof message === 'string' ) {
408
+ try {
409
+ childError = JSON . parse ( message ) ;
410
+ } catch ( errJson ) {
411
+ childError = message ;
403
412
}
404
- } ) ;
405
-
406
- // check if job is still alive
407
- const checkCancel = ( ) =>
408
- setTimeout ( ( ) => {
409
- if ( this . canceled ) {
410
- try {
411
- child . send ( 'cancel' ) ;
412
- console . info ( 'canceled child' , this . attrs . name , this . attrs . _id ) ;
413
- } catch ( err ) {
414
- console . log ( 'cannot send cancel to child' ) ;
415
- }
416
- } else if ( stillRunning ) {
417
- setTimeout ( checkCancel , 10000 ) ;
418
- }
419
- } ) ;
420
- checkCancel ( ) ;
413
+ } else {
414
+ childError = message ;
415
+ }
421
416
} ) ;
422
- } finally {
423
- stillRunning = false ;
424
- }
417
+ } ) ;
425
418
} else {
426
419
await this . runJob ( ) ;
427
420
}
@@ -440,6 +433,7 @@ export class Job<DATA = unknown | void> {
440
433
this . agenda . emit ( `fail:${ this . attrs . name } ` , error , this ) ;
441
434
log ( '[%s:%s] has failed [%s]' , this . attrs . name , this . attrs . _id , error . message ) ;
442
435
} finally {
436
+ this . forkedChild = undefined ;
443
437
this . attrs . lockedAt = undefined ;
444
438
try {
445
439
await this . agenda . db . saveJobState ( this ) ;
0 commit comments