@@ -4,6 +4,7 @@ import { IAgendaStatus } from './types/AgendaStatus';
4
4
import { IJobDefinition } from './types/JobDefinition' ;
5
5
import { JobProcessingQueue } from './JobProcessingQueue' ;
6
6
import type { Agenda } from './index' ;
7
+ import type { IJobParameters } from './types/JobParameters' ;
7
8
8
9
const log = debug ( 'agenda:jobProcessor' ) ;
9
10
@@ -333,7 +334,6 @@ export class JobProcessor {
333
334
334
335
this . enqueueJob ( job ) ;
335
336
await this . jobQueueFilling ( name ) ;
336
- // this.jobProcessing();
337
337
} else {
338
338
log . extend ( 'jobQueueFilling' ) ( 'Cannot lock job [%s]' , name ) ;
339
339
}
@@ -344,22 +344,22 @@ export class JobProcessor {
344
344
345
345
/**
346
346
* Internal method that processes any jobs in the local queue (array)
347
+ * handledJobs keeps list of already processed jobs
347
348
* @returns {undefined }
348
349
*/
349
- private async jobProcessing ( ) {
350
+ private async jobProcessing ( handledJobs : IJobParameters [ '_id' ] [ ] = [ ] ) {
350
351
// Ensure we have jobs
351
352
if ( this . jobQueue . length === 0 ) {
352
353
return ;
353
354
}
354
355
355
356
this . localQueueProcessing += 1 ;
356
357
357
- let jobEnqueued = false ;
358
358
try {
359
359
const now = new Date ( ) ;
360
360
361
361
// Check if there is any job that is not blocked by concurrency
362
- const job = this . jobQueue . returnNextConcurrencyFreeJob ( this . jobStatus ) ;
362
+ const job = this . jobQueue . returnNextConcurrencyFreeJob ( this . jobStatus , handledJobs ) ;
363
363
364
364
if ( ! job ) {
365
365
log . extend ( 'jobProcessing' ) ( '[%s:%s] there is no job to process' ) ;
@@ -380,7 +380,7 @@ export class JobProcessor {
380
380
job . attrs . name ,
381
381
job . attrs . _id
382
382
) ;
383
- jobEnqueued = await this . runOrRetry ( job ) ;
383
+ this . runOrRetry ( job ) ;
384
384
} else {
385
385
const runIn = job . attrs . nextRunAt . getTime ( ) - now . getTime ( ) ;
386
386
log . extend ( 'jobProcessing' ) (
@@ -392,11 +392,12 @@ export class JobProcessor {
392
392
setTimeout ( ( ) => {
393
393
this . jobProcessing ( ) ;
394
394
} , runIn ) ;
395
- jobEnqueued = true ;
396
395
}
397
- if ( this . localQueueProcessing < this . maxConcurrency && jobEnqueued ) {
396
+
397
+ if ( this . localQueueProcessing < this . maxConcurrency ) {
398
398
// additionally run again and check if there are more jobs that we can process right now (as long concurrency not reached)
399
- setImmediate ( ( ) => this . jobProcessing ( ) ) ;
399
+ handledJobs . push ( job . attrs . _id ) ;
400
+ setImmediate ( ( ) => this . jobProcessing ( handledJobs ) ) ;
400
401
}
401
402
} finally {
402
403
this . localQueueProcessing -= 1 ;
@@ -407,15 +408,15 @@ export class JobProcessor {
407
408
* Internal method that tries to run a job and if it fails, retries again!
408
409
* @returns {boolean } processed a job or not
409
410
*/
410
- private async runOrRetry ( job : Job ) : Promise < boolean > {
411
+ private async runOrRetry ( job : Job ) : Promise < void > {
411
412
if ( ! this . isRunning ) {
412
413
// const a = new Error();
413
414
// console.log('STACK', a.stack);
414
415
log . extend ( 'runOrRetry' ) (
415
416
'JobProcessor got stopped already while calling runOrRetry, returning!' ,
416
417
this
417
418
) ;
418
- return false ;
419
+ return ;
419
420
}
420
421
421
422
this . jobQueue . remove ( job ) ;
@@ -448,109 +449,106 @@ export class JobProcessor {
448
449
449
450
this . lockedJobs . splice ( lockedJobIndex , 1 ) ;
450
451
this . updateStatus ( job . attrs . name , 'locked' , - 1 ) ;
451
- return true ;
452
+ return ;
452
453
}
453
454
454
- const runJob = async ( ) => {
455
- // Add to local "running" queue
456
- this . runningJobs . push ( job ) ;
457
- this . updateStatus ( job . attrs . name , 'running' , 1 ) ;
458
-
459
- try {
460
- log . extend ( 'runOrRetry' ) ( '[%s:%s] processing job' , job . attrs . name , job . attrs . _id ) ;
461
-
462
- // check if the job is still alive
463
- const checkIfJobIsStillAlive = ( ) => {
464
- // check every "this.agenda.definitions[job.attrs.name].lockLifetime / 2"" (or at mininum every processEvery)
465
- return new Promise ( ( resolve , reject ) =>
466
- setTimeout ( ( ) => {
467
- // when job is not running anymore, just finish
468
- if ( ! job . isRunning ( ) ) {
469
- resolve ( ) ;
470
- return ;
471
- }
472
-
473
- if ( job . isDead ( ) ) {
474
- reject (
475
- new Error (
476
- `execution of '${ job . attrs . name } ' canceled, execution took more than ${
477
- this . agenda . definitions [ job . attrs . name ] . lockLifetime
478
- } ms. Call touch() for long running jobs to keep them alive.`
479
- )
480
- ) ;
481
- return ;
482
- }
483
-
484
- resolve ( checkIfJobIsStillAlive ( ) ) ;
485
- } , Math . max ( this . processEvery , this . agenda . definitions [ job . attrs . name ] . lockLifetime / 2 ) )
486
- ) ;
487
- } ;
455
+ // Add to local "running" queue
456
+ this . runningJobs . push ( job ) ;
457
+ this . updateStatus ( job . attrs . name , 'running' , 1 ) ;
458
+
459
+ try {
460
+ log . extend ( 'runOrRetry' ) ( '[%s:%s] processing job' , job . attrs . name , job . attrs . _id ) ;
461
+
462
+ // check if the job is still alive
463
+ const checkIfJobIsStillAlive = ( ) => {
464
+ // check every "this.agenda.definitions[job.attrs.name].lockLifetime / 2"" (or at mininum every processEvery)
465
+ return new Promise ( ( resolve , reject ) =>
466
+ setTimeout ( ( ) => {
467
+ // when job is not running anymore, just finish
468
+ if ( ! job . isRunning ( ) ) {
469
+ resolve ( ) ;
470
+ return ;
471
+ }
472
+
473
+ if ( job . isDead ( ) ) {
474
+ reject (
475
+ new Error (
476
+ `execution of '${ job . attrs . name } ' canceled, execution took more than ${
477
+ this . agenda . definitions [ job . attrs . name ] . lockLifetime
478
+ } ms. Call touch() for long running jobs to keep them alive.`
479
+ )
480
+ ) ;
481
+ return ;
482
+ }
483
+
484
+ resolve ( checkIfJobIsStillAlive ( ) ) ;
485
+ } , Math . max ( this . processEvery , this . agenda . definitions [ job . attrs . name ] . lockLifetime / 2 ) )
486
+ ) ;
487
+ } ;
488
+
489
+ // CALL THE ACTUAL METHOD TO PROCESS THE JOB!!!
490
+ await Promise . race ( [ job . run ( ) , checkIfJobIsStillAlive ( ) ] ) ;
488
491
489
- // CALL THE ACTUAL METHOD TO PROCESS THE JOB!!!
490
- await Promise . race ( [ job . run ( ) , checkIfJobIsStillAlive ( ) ] ) ;
492
+ log . extend ( 'runOrRetry' ) (
493
+ '[%s:%s] processing job successfull' ,
494
+ job . attrs . name ,
495
+ job . attrs . _id
496
+ ) ;
491
497
498
+ // Job isn't in running jobs so throw an error
499
+ if ( ! this . runningJobs . includes ( job ) ) {
492
500
log . extend ( 'runOrRetry' ) (
493
- '[%s:%s] processing job successfull' ,
494
- job . attrs . name ,
501
+ '[%s] callback was called, job must have been marked as complete already' ,
495
502
job . attrs . _id
496
503
) ;
504
+ throw new Error (
505
+ `callback already called - job ${ job . attrs . name } already marked complete`
506
+ ) ;
507
+ }
508
+ } catch ( err ) {
509
+ job . canceled = err ;
510
+ log . extend ( 'runOrRetry' ) (
511
+ '[%s:%s] processing job failed' ,
512
+ job . attrs . name ,
513
+ job . attrs . _id ,
514
+ err
515
+ ) ;
516
+ job . agenda . emit ( 'error' , err ) ;
517
+ } finally {
518
+ // Remove the job from the running queue
519
+ let runningJobIndex = this . runningJobs . indexOf ( job ) ;
520
+ if ( runningJobIndex === - 1 ) {
521
+ // lookup by id
522
+ runningJobIndex = this . runningJobs . findIndex (
523
+ j => j . attrs . _id ?. toString ( ) === job . attrs . _id ?. toString ( )
524
+ ) ;
525
+ }
526
+ if ( runningJobIndex === - 1 ) {
527
+ // eslint-disable-next-line no-unsafe-finally
528
+ throw new Error ( `cannot find job ${ job . attrs . _id } in running jobs queue?` ) ;
529
+ }
530
+ this . runningJobs . splice ( runningJobIndex , 1 ) ;
531
+ this . updateStatus ( job . attrs . name , 'running' , - 1 ) ;
497
532
498
- // Job isn't in running jobs so throw an error
499
- if ( ! this . runningJobs . includes ( job ) ) {
500
- log . extend ( 'runOrRetry' ) (
501
- '[%s] callback was called, job must have been marked as complete already' ,
502
- job . attrs . _id
503
- ) ;
504
- throw new Error (
505
- `callback already called - job ${ job . attrs . name } already marked complete`
506
- ) ;
507
- }
508
- } catch ( err ) {
509
- job . canceled = err ;
510
- log . extend ( 'runOrRetry' ) (
511
- '[%s:%s] processing job failed' ,
512
- job . attrs . name ,
513
- job . attrs . _id ,
514
- err
533
+ // Remove the job from the locked queue
534
+ let lockedJobIndex = this . lockedJobs . indexOf ( job ) ;
535
+ if ( lockedJobIndex === - 1 ) {
536
+ // lookup by id
537
+ lockedJobIndex = this . lockedJobs . findIndex (
538
+ j => j . attrs . _id ?. toString ( ) === job . attrs . _id ?. toString ( )
515
539
) ;
516
- job . agenda . emit ( 'error' , err ) ;
517
- } finally {
518
- // Remove the job from the running queue
519
- let runningJobIndex = this . runningJobs . indexOf ( job ) ;
520
- if ( runningJobIndex === - 1 ) {
521
- // lookup by id
522
- runningJobIndex = this . runningJobs . findIndex (
523
- j => j . attrs . _id ?. toString ( ) === job . attrs . _id ?. toString ( )
524
- ) ;
525
- }
526
- if ( runningJobIndex === - 1 ) {
527
- // eslint-disable-next-line no-unsafe-finally
528
- throw new Error ( `cannot find job ${ job . attrs . _id } in running jobs queue?` ) ;
529
- }
530
- this . runningJobs . splice ( runningJobIndex , 1 ) ;
531
- this . updateStatus ( job . attrs . name , 'running' , - 1 ) ;
532
-
533
- // Remove the job from the locked queue
534
- let lockedJobIndex = this . lockedJobs . indexOf ( job ) ;
535
- if ( lockedJobIndex === - 1 ) {
536
- // lookup by id
537
- lockedJobIndex = this . lockedJobs . findIndex (
538
- j => j . attrs . _id ?. toString ( ) === job . attrs . _id ?. toString ( )
539
- ) ;
540
- }
541
- if ( lockedJobIndex === - 1 ) {
542
- // eslint-disable-next-line no-unsafe-finally
543
- throw new Error ( `cannot find job ${ job . attrs . _id } in locked jobs queue?` ) ;
544
- }
545
- this . lockedJobs . splice ( lockedJobIndex , 1 ) ;
546
- this . updateStatus ( job . attrs . name , 'locked' , - 1 ) ;
547
540
}
541
+ if ( lockedJobIndex === - 1 ) {
542
+ // eslint-disable-next-line no-unsafe-finally
543
+ throw new Error ( `cannot find job ${ job . attrs . _id } in locked jobs queue?` ) ;
544
+ }
545
+ this . lockedJobs . splice ( lockedJobIndex , 1 ) ;
546
+ this . updateStatus ( job . attrs . name , 'locked' , - 1 ) ;
547
+ }
548
548
549
- // Re-process jobs now that one has finished
550
- setImmediate ( ( ) => this . jobProcessing ( ) ) ;
551
- } ;
552
- runJob ( ) ;
553
- return true ;
549
+ // Re-process jobs now that one has finished
550
+ setImmediate ( ( ) => this . jobProcessing ( ) ) ;
551
+ return ;
554
552
}
555
553
556
554
// Run the job later
@@ -560,7 +558,6 @@ export class JobProcessor {
560
558
job . attrs . _id
561
559
) ;
562
560
this . enqueueJob ( job ) ;
563
- return false ;
564
561
}
565
562
566
563
private updateStatus ( name : string , key : 'locked' | 'running' , number : - 1 | 1 ) {
0 commit comments