I am working on a Hangfire queue implementation to handle requests to an external API.
I can only handle 1 request at a time, so I set the WorkerCount to 1.
The API runs long running tasks and can only work with one task at the time.
I am using a fire-and-forget job queue, and the idea is to call the API, which will create an async call to the long running task, and return to the caller the confirmation that the task has been initialised. Once finished, the caller should be notified about the result of the execution.
If I leave it like this, then the Hangfire queue will finish the job successfully and immediately take the next job from the queue and call the API again, which I don’t want to do as the API can only run one task at a time.
So I decided to add a custom state to the hangfire state machine so that after processing, the job would be in that state instead of being finished. Once the API is done with the long running task, the idea is to change the job status to “successful” and finish the job.
This is the code I use for the new state:
public class WaitingModelCompletionState : IState
{
public static readonly string StateName = "WaitingModelCompletion";
public string Name => StateName;
public string Reason => "Waiting for the model completion from an external service.";
public bool IsFinal => false;
public bool IgnoreJobLoadException => false;
public Dictionary<string, string> SerializeData() => new Dictionary<string, string>();
public class Handler : IStateHandler
{
public const string StateStatTKey = "stats:waitinmodelcompletion";
public string StateName => WaitingModelCompletionState.StateName;
public void Apply(ApplyStateContext context, IWriteOnlyTransaction transaction)
{
transaction.IncrementCounter(StateStatTKey);
}
public void Unapply(ApplyStateContext context, IWriteOnlyTransaction transaction)
{
transaction.DecrementCounter(StateStatTKey);
}
}
}
public class WaitingModelCompletionFilter : IElectStateFilter
{
public void OnStateElection(ElectStateContext context)
{
if (context.CurrentState == ProcessingState.StateName
&& context.CandidateState is SucceededState
)
{
context.CandidateState = new WaitingModelCompletionState();
}
}
}```
However, for some reason the IsFinal attribute is ignored and the job is terminated even though it is in the new state.
This is my output in the dashboard.
![image|690x415](upload://cdvsMQY9BIFWkUJKKgOqpGLAvJ7.png)
And this is my output if I move from enqueed to the new state, instead of moving from processing to the new state
![image|690x324](upload://6XZaNALVWorTSb02hej5pG1xxtX.png)