CancellationToken from IJobCancellationToken


#1

Moving discussion from GitHub Issue to here. What is the reasoning behind not having IJobCancellationToken expose a CancellationToken as part of its definition? That would allow it to integrate more cleanly with the other async APIs. It would also allow jobs to be notified immediately upon cancellation as opposed to having to continually poll the ThrowIfCancellationRequested method. I see that ServerJobCancellationToken has a CancellationToken already. It would be simple enough to have JobCancellationToken return CancellationToken.None or allow a constructor override to allow you to pass in your own.


#2

The ThrowIfCancellationRequested method throws OperationCanceledException when any of the following events occur:

  • Hangfire Server is shutting down - Stop or Dispose method has been called. Usual CancellationToken is being used here.
  • Background job was aborted - its state was changed during the processing. This check requires round-trip to the job storage.

So, if you simply expose the CancellationToken instance to the IJobCancellationToken interface, you’ll end with broken abstraction that will not work in half cases. That is why it is not exposed.


#3

Fair enough. Does it at least make sense to add Register methods similar to what CancellationToken provides so that someone could get immediate notification as opposed to continually polling? At least that way, a job could wrap the token in its own CancellationTokenSource for better integration with the async APIs so that tasks cancel immediately upon the job token being signaled.


#4

CancellationToken implementation that is being fired once any of the described above events occur requires polling, since the latter event’s source defined in the job storage.

However, we may introduce the IJobCancellationToken.ShutdownToken (need to consider the naming first) that will be fired on server shutdown only. This will not solve the entire problem, however this can solve at least the largest part without requiring to use the polling technique.


#5

I am trying to find a way to prevent the IJobCancellationToken and Hangfire dependency to propagate through all my processing code shared by other projects. I like the example of the LongRunningJob (described here: https://github.com/HangfireIO/Hangfire/issues/211) unwrapping the IJobCancellationToken into a regular CancellationToken for the OutstandingOperation which does just that. I would like to go further.

Without IJobCancellationToken and using IoC containers, I am able to have fully Hangfire-independent background processing assembly, which is quite nice. I am trying to achieve implement something similar.

If we want to stick with a generic CancellationToken, one of the problem is that IsJobAborted is being polled and CancellationToken requires its CancellationTokenSource.Cancel to be called by an external event. There would need to be a background task to monitor all running processes and cancel.

    public void ThrowIfCancellationRequested()
    {
        _shutdownToken.ThrowIfCancellationRequested();

        if (IsJobAborted())
        {
            throw new JobAbortedException();
        }
    }

Is there any clever way to solve this dependency issue using IoC?


#6

is there a way to delete a processing job and at the same time get it canceled/aborted?


#8

This happened with the call to an Api made in .netCore 3.1