Search code examples
c#jobsaspnetboilerplateabp-frameworkcontinuewith

IBackgroundJobManager sequential jobs using 'ContinueWith'


I am using IBackgroundJobManager with Hangfire integration.

Use case:

I am processing a single uploaded file. After the file is saved, I would like to start two separate Abp.BackgroundJobs sequentially. Only after the first job completes, should the second job start.

Here is my code:

var measureJob1 = await _backgroundJobManager.EnqueueAsync<FileProcessBackgroundJob, FileProcessJobArgsDto>(
        new FileProcessJobArgsDto
        {
            Id = Id,
            User = user,
        })
    .ContinueWith<AnalyticsBackgroundJob<AnalyticsJobArgsDto>>("measureJob",x => x);

Problem:

I can not figure out the syntax for what I need when using the .ContinueWith<???>(???).


Solution

  • This seems to be an XY Problem.

    How to start the second background job after the first completes? (Problem X)

    There is no support for guaranteeing the sequential and conditional execution of jobs.

    That said, background jobs are automatically retried, which allows for Way 3 below.

    So, you can effectively achieve that by one of these ways:

    1. Combine the two jobs into one job.
    2. Enqueue the second job inside the first job.
    3. Enqueue both jobs (you don't need to use ContinueWith, await is much neater). In the second job, check if the first job created what it needed to. Otherwise, throw an exception and rely on retry.

    What is the syntax for what I need when using ContinueWith? (Solution Y)

    There is no syntax for that, other than a less desirable variant of Way 3.

    Task.ContinueWith is a C# construct that runs after the EnqueueAsync task, not the actual background job.

    The syntax for Way 3 with ContinueWith would be something like:

    var measureJobId = await _backgroundJobManager.EnqueueAsync<FileProcessBackgroundJob, FileProcessJobArgsDto>(
            new FileProcessJobArgsDto
            {
                Id = Id,
                User = user,
            }
        )
        .ContinueWith(task => _backgroundJobManager.EnqueueAsync<AnalyticsBackgroundJob, AnalyticsJobArgsDto>(
            new AnalyticsJobArgsDto("measureJob")
        )
        .Unwrap();
    

    Compare that to:

    var processJobId = await _backgroundJobManager.EnqueueAsync<FileProcessBackgroundJob, FileProcessJobArgsDto>(
            new FileProcessJobArgsDto
            {
                Id = Id,
                User = user,
            }
        );
    
    var measureJobId = await _backgroundJobManager.EnqueueAsync<AnalyticsBackgroundJob, AnalyticsJobArgsDto>(
            new AnalyticsJobArgsDto("measureJob")
        );