HangfireIO / Hangfire

An easy way to perform background job processing in .NET and .NET Core applications. No Windows Service or separate process required
https://www.hangfire.io
Other
9.35k stars 1.69k forks source link

Run jobs inside transaction scope #2420

Open MikhailIvanou opened 3 months ago

MikhailIvanou commented 3 months ago

Hi everyone,

correct me please if I'm wrong, but out of the blue, I didn't find an acceptable way to run jobs inside a TransactionScope...

I mean, if you have a look at CoreBackgroundJobPerformer you will notice that there is no an extension point inside an opened ServiceScope.

However, normally I would start and commit a transaction inside a scope, roughly something like that...

    public async object Perform(PerformContext context)
    {
        using (var scope = _activator.BeginScope(context))
        {
            //
            // an extension point (like a new Job Filter type)
            //
            await ScopeHasBeenCreated(scope);

            object instance = null;

            if (context.BackgroundJob.Job == null)
            {
                throw new InvalidOperationException("Can't perform a background job with a null job.");
            }

            if (!context.BackgroundJob.Job.Method.IsStatic)
            {
                instance = scope.Resolve(context.BackgroundJob.Job.Type);

                if (instance == null)
                {
                    throw new InvalidOperationException(
                        $"JobActivator returned NULL instance of the '{context.BackgroundJob.Job.Type}' type.");
                }
            }

            var arguments = SubstituteArguments(context);
            var result = InvokeMethod(context, instance, arguments);

            //
            // an extension point (like a new Job Filter type)
            //
            await BeforeScopeDestroyed(scope);

            return result;
        }
    }

    async Task ScopeHasBeenCreated(IServiceScope scope)
    {
      await  scope.ServiceProvider.GetServices<IUnitOfWork>().BeginTransaction();
    }

    async Task BeforeScopeDestroyed(IServiceScope scope)
    {
        await scope.ServiceProvider.GetServices<IUnitOfWork>().Commit();
    }

Barely can we use existing job filters to start/stop a UoW, because we are not inside a DI scope of a job.

What do you think about it and do you see any problems to add two Job filters to handle this problem?

IwanowM commented 2 months ago

thoughts?