From 8cf839098f3571dfe37f385bcb39a1c24deef115 Mon Sep 17 00:00:00 2001 From: Eric Peterson Date: Mon, 12 Feb 2024 11:42:51 -0700 Subject: [PATCH] feat(Job): Add support for `before` and `after` lifecycle methods A `before` and/or an `after` method can be defined on the Job instance. This will be called as a lifecycle method either `before` or `after` the job is ran. --- models/Providers/AbstractQueueProvider.cfc | 6 ++++ models/Providers/SyncProvider.cfc | 6 ++++ tests/resources/AbstractQueueProviderSpec.cfc | 28 +++++++++++++++++++ .../app/models/Jobs/BeforeAndAfterJob.cfc | 15 ++++++++++ 4 files changed, 55 insertions(+) create mode 100644 tests/resources/app/models/Jobs/BeforeAndAfterJob.cfc diff --git a/models/Providers/AbstractQueueProvider.cfc b/models/Providers/AbstractQueueProvider.cfc index 010fdf4..c6f8af2 100644 --- a/models/Providers/AbstractQueueProvider.cfc +++ b/models/Providers/AbstractQueueProvider.cfc @@ -109,6 +109,9 @@ component accessors="true" { } beforeJobRun( job ); + if ( structKeyExists( job, "before" ) ) { + job.before(); + } variables.interceptorService.announce( "onCBQJobMarshalled", { "job" : job } ); @@ -153,6 +156,9 @@ component accessors="true" { } ); + if ( structKeyExists( job, "after" ) ) { + job.after(); + } afterJobRun( job ); ensureSuccessfulBatchJobIsRecorded( job ); diff --git a/models/Providers/SyncProvider.cfc b/models/Providers/SyncProvider.cfc index 76bbfa7..3b80702 100644 --- a/models/Providers/SyncProvider.cfc +++ b/models/Providers/SyncProvider.cfc @@ -41,6 +41,9 @@ component accessors="true" extends="AbstractQueueProvider" { } beforeJobRun( arguments.job ); + if ( structKeyExists( job, "before" ) ) { + job.before(); + } variables.interceptorService.announce( "onCBQJobMarshalled", { "job" : arguments.job } ); @@ -83,6 +86,9 @@ component accessors="true" extends="AbstractQueueProvider" { } ); + if ( structKeyExists( job, "after" ) ) { + job.after(); + } afterJobRun( job ); ensureSuccessfulBatchJobIsRecorded( job ); diff --git a/tests/resources/AbstractQueueProviderSpec.cfc b/tests/resources/AbstractQueueProviderSpec.cfc index 7dad4e1..ba3c99b 100644 --- a/tests/resources/AbstractQueueProviderSpec.cfc +++ b/tests/resources/AbstractQueueProviderSpec.cfc @@ -2,6 +2,11 @@ component extends="tests.resources.ModuleIntegrationSpec" appMapping="/app" { function run() { describe( "queue provider - #getProviderMapping()#", function() { + beforeEach( function() { + structDelete( application, "jobBeforeCalled" ); + structDelete( application, "jobAfterCalled" ); + } ); + it( "can manually release a job back on to a queue with a given delay", function() { var provider = getProvider(); $spy( provider, "releaseJob" ); @@ -78,6 +83,29 @@ component extends="tests.resources.ModuleIntegrationSpec" appMapping="/app" { var callLog = provider.$callLog()[ "releaseJob" ][ 1 ]; expect( provider.getBackoffForJob( callLog[ 1 ], callLog[ 2 ] ) ).toBe( 2, "The delay [2] should have been passed to the provider" ); } ); + + it( "calls a before and after method if present as lifecycle methods", () => { + var provider = getProvider(); + var workerPool = makeWorkerPool( provider ); + var job = getInstance( "BeforeAndAfterJob" ) + .setId( randRange( 1, 1000 ) ); + + param application.jobBeforeCalled = false; + param application.jobAfterCalled = false; + + expect( application.jobBeforeCalled ).toBeFalse(); + expect( application.jobAfterCalled ).toBeFalse(); + + // work the job + var jobFuture = provider.marshalJob( job, workerPool ); + // if it is an async operation, wait for it to finish + if ( !isNull( jobFuture ) ) { + jobFuture.get(); + } + + expect( application.jobBeforeCalled ).toBeTrue( "The before method should have been called" ); + expect( application.jobAfterCalled ).toBeTrue( "The after method should have been called" ); + } ); } ); } diff --git a/tests/resources/app/models/Jobs/BeforeAndAfterJob.cfc b/tests/resources/app/models/Jobs/BeforeAndAfterJob.cfc new file mode 100644 index 0000000..9b9202e --- /dev/null +++ b/tests/resources/app/models/Jobs/BeforeAndAfterJob.cfc @@ -0,0 +1,15 @@ +component extends="cbq.models.Jobs.AbstractJob" { + + function handle() { + // do nothing + } + + function before() { + application.jobBeforeCalled = true; + } + + function after() { + application.jobAfterCalled = true; + } + +} \ No newline at end of file