Use Hangfire job id in the code

I’m doing a Fire-and-Forget method invocation like this.

BackgroundJob.Enqueue(() => SendEmail(name));

I would like to use the job id inside the SendEmail() method. Is it possible?

1 Like

You can set up a filter class like this:

    public class GetJobId : JobFilterAttribute,
        IClientFilter, IServerFilter, IElectStateFilter, IApplyStateFilter
    {
           [ThreadStatic]
            private static string _jobId;
            public static string JobId { get { return _jobId; } set { _jobId = value; } }
            public void OnPerforming(PerformingContext filterContext)
            {
                   _jobId = filterContext.BackgroundJob.Id;
            }
    }

And your method like:

   [GetJobId ()]
   public void SendEmail(string name)
   {
           string jobId = GetJobId.JobId;
   }

Hope this help.

3 Likes

First, never use a static field for that, even if marked with a ThreadStaticAttribute. The job could be executed on a different thread (for example, Task-based jobs), and you’ll get an empty result.

For achieving your goal, just add PerformContext to your job method:

public void SendEmail(string name, PerformContext context)
{
   string jobId = context.BackgroundJob.Id;
}

And pass null for it when enqueuing a job:

BackgroundJob.Enqueue(() => SendEmail(name, null));

It will be substituted with a correct context when the job is actually performed.

8 Likes

Another idea is to hook into the activation of the job (when the instance of the job object is constructed) and inject in the job id as a property. I’ve been messing around with this idea via https://github.com/Silvenga/Hangfire.ActivationExtensions (still beta, but simple enough).

Considering your job implements the interface (consider better naming):

interface IJobIdAble
{
	string HangfireJobId { get; }
}

Then you can create and add the filter (from my project):

public class IJobIdAbleFilter : IJobActivatorFilter
{
	/// <summary>
	/// Called after the job is constructed by the current activator.
	/// </summary>
	/// <param name="jobType">The type of the job being created.</param>
	/// <param name="activatedJob">The object created by the activator. Should be of type found within jobType.</param>
	/// <param name="context"></param>
	void OnMaterialized(Type jobType, object activatedJob, [CanBeNull] JobActivatorContext context)
	{
		var idAble = activatedJob as IJobIdAble;
		if (idAble != null)
		{
			idAble.HangfireJobId = context.BackgroundJob.Id
		}
	}
	
	// ... override other things...
}

Than you can access the needed information via:

public void SendEmail(string name, PerformContext context)
{
	string jobId = HangfireJobId;
}

Adding PerformContext to the job method is simple and works as expected. Thanks @pieceofsummer

Can you tell me how to get Job Id of my simple function
BackgroundJob.Enqueue(() => TextBuffer.Extract(“Extraction Completed”));
The above function is just to display the string i need to get the job id of that specific

It worked thanks but now it is deprecated and from version 2.0.0 onwards this will be removed, so you can use
> public void SendEmail(string name, PerformContext context)

    {
       string jobId = context.BackgroundJob.Id;
    }
1 Like