After searching & reading possibly every discussion related to the topic in question, there seemed not to be a clear (or even unclear) solution to this.
I have a job filter that I want to apply to every job. What I want to do is: when the job fails (goes to FailedState
, which happens when the max retry attemps exceed OR it is thrown in that state manually), I want to log a custom, user-friendly exception message to the database (my custom table).
public class WorkflowJobFailureAttribute : JobFilterAttribute, IApplyStateFilter {
public WorkflowJobFailureAttribute(IServiceProvider serviceProvider) {
// Getting my required services here
}
public void OnStateApplied(ApplyStateContext context, IWriteOnlyTransaction transaction)
{
var failedState = context.NewState as FailedState;
if (failedState != null) {
// - HANDLE FAILED STATE HERE -
// You can get the exception (which is of type `Exception`) using: `failedState.Exception`
}
}
}
But every darn example/suggestion I was was about registering the filter globally (GlobalJobFilters.Filters.Add(new WorkflowJobFailureAttribute(serviceProvider));
in Startup.cs
). But this is the ROOT service provider, so it will not work with scoped lifetime.
There is a possible 'workaround', suggested by balazs hideghety in the comments here. But before diving deep into that (because it feels like a 'distant' solution), I would like to know: has anyone, in his experience, solved this problem?
CodePudding user response:
Inject a scoped service provider factory and then create the scoped service provider as needed
public class WorkflowJobFailureAttribute : JobFilterAttribute, IApplyStateFilter {
private readonly IServiceScopeFactory scopeFactory;
public WorkflowJobFailureAttribute(IServiceScopeFactory scopeFactory) {
this.scopeFactory = scopeFactory;
}
public void OnStateApplied(ApplyStateContext context, IWriteOnlyTransaction transaction) {
var failedState = context.NewState as FailedState;
if (failedState != null) {
using (IServiceScope scope = scopeFactory.CreateScope()) {
IServiceProvider serviceProvider = scope.ServiceProvider;
// Getting my required services here
// - HANDLE FAILED STATE HERE -
// You can get the exception (which is of type `Exception`) using: `failedState.Exception`
}
}
}
}
In the preceding code, an explicit scope is created and the service provider can be used to resolve scoped services.