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.41k stars 1.71k forks source link

Any way to access JobActivator/Scope in JobFilter and replace job parameters? #1493

Open xumix opened 5 years ago

xumix commented 5 years ago

Why do I need this: I'm trying to replace PerformContext-like object in my job execution method parameters. So the first thing I've encountered is: I can't get current activator scope, therefore I can't resolve the needed parameter within the scope. The second problem is: I can't find a way to replace job parameters since filterContext.BackgroundJob.Job.Args is readonly.

This is a sample which demonstrates the problem:

public void OnPerforming(PerformingContext filterContext)
        {
            var jobContextParameter = filterContext.BackgroundJob.Job.Method.GetParameters()
                .FirstOrDefault(f => f.ParameterType == typeof(IJobContext));

            if (jobContextParameter != null)
            {
                filterContext.BackgroundJob.Job.Args[0] = container.Resolve<IJobContext>();
            }
        }
kashyapus commented 5 years ago

I wanted something similar in our implementation as I wanted to implement UOW and use the same container that the job context is using, so that we can commit db transaction at the end of the job.

kashyapus commented 4 years ago

I had to do a work around but I achieved solution to this by putting container used by JobActivator/JobActivatorScope onto a thread safe static property that can be accessed anywhere in custom filter.

    public class JobContext
    {
        [ThreadStatic]
        public static IContainer Container;

        public static void Reset()
        {
            Container?.Dispose();
        }
    }

In performing filter create a new child container (parent container injected into filter) for each job, setting the JobContext.Container and then using it in JobActivatorScope to create an instance of your job and disposing it in Performed filter method by calling JobContext.Reset().

Sorry for not being detailed enough, but I hope can give you an approach to solve this. It's a little hackish and I am not a big fan of it but it achieves end goal.

In essence take control of your destiny.

DavidJBall commented 4 years ago

I had to do a work around but I achieved solution to this by putting container used by JobActivator/JobActivatorScope onto a thread safe static property that can be accessed anywhere in custom filter.

    public class JobContext
    {
        [ThreadStatic]
        public static IContainer Container;

        public static void Reset()
        {
            Container?.Dispose();
        }
    }

In performing filter create a new child container (parent container injected into filter) for each job, setting the JobContext.Container and then using it in JobActivatorScope to create an instance of your job and disposing it in Performed filter method by calling JobContext.Reset().

Sorry for not being detailed enough, but I hope can give you an approach to solve this. It's a little hackish and I am not a big fan of it but it achieves end goal.

In essence take control of your destiny.

Did you manage to improve on your solution? I'm looking to share the scope of dependencies between my job filter and the job itself and using a static IContainer is just too much of a hack for me :)