HangfireIO / HangfireIO/Hangfire
Running a job from a different AppDomain
- Dominant language
- C#
- Stars
- 10.1k
- Forks
- 1.8k
- Avg merge
- 1h 19m
- Merged PRs (30d)
- 1
Description
The approach we are taking is to treat job solutions as separate from the server (think Plug-Ins). Let's see if I can explain:
The server is a self-hosted OWIN app within a Windows Service project using a RESTful controller to take job requests (JSON), and hosts Hangfire. When the controller gets a good POST, the app spins up a new AppDomain, loads the target job (resides in a directory underneath the main app) then queues it to hangfire.
When hangfire tries to run the job it is crashing as it cannot now find the references it was compiled with. I am assuming this is because hangfire is running in the AppDomain of the main app and does not know anything about the (temp) AppDomain the Job was initialized in.
Is there a way to run the job itself in its own AppDomain inside of hangfire?
Maybe something like this in another (overloaded) Enqueue() method?
```c#
public class BaseHandler : MarshalByRefObject
{
protected internal AppDomain JobAppDomain;
protected internal BaseHandler JobHandler;
protected internal void SetupInstance(string jobClassName, string jobName)
{
var ads = new AppDomainSetup
{
ApplicationBase = new FileInfo(Assembly.GetExecutingAssembly().Location).DirectoryName,
DisallowBindingRedirects = false,
DisallowCodeDownload = true,
PrivateBinPath = jobClassName,
ApplicationName = jobName,
};
JobAppDomain = AppDomain.CreateDomain(jobName, null, ads);
JobHandler = (BaseHandler)JobAppDomain.CreateInstanceAndUnwrap(typeof(BaseHandler).Assembly.FullName, typeof(BaseHandler).FullName);
}
protected internal IJob GetJob(string jobClassName)
{
var assembly = Assembly.LoadFrom(jobClassName + @"\" + jobClassName + ".dll");
var assemblyType = assembly.GetType(info.AssemblyName);
return Activator.CreateInstance(assemblyType) as IJob;
}
}
```
NOTE: IJob is an interface in our grand scheme!
We use the Base Class in our handlers like:
```c#
public class JobAdHocHandler : BaseHandler, IJobHandler
{
public MinimumResultModel Handle(MinimumCommandModel message)
{
var result = new MinimumResultModel {Id = "-1", PayloadAsString = message.FullPayloadString};
try
{
var info = message.MinimumPayload.JobInfo;
SetupInstance(info.JobClassName, info.JobName);
var job = JobHandler.GetJob(info.JobClassName);
result.Id = BackgroundJob.Enqueue(() => job.Execute(null, message.FullPayloadString, JobCancellationToken.Null));
}
catch (Exception ex)
{
Log.Logger.Fatal(ex, ex.Message);
result.Exception = ex;
}
AppDomain.Unload(JobAppDomain);
return result;
}
public bool AppliesTo(JobType jobType) => jobType == JobType.AdHoc;
}
```
Thoughts?
Contributor guide
Research direction
Start by tracing JobAdHocHandler.Handle through BaseHandler.SetupInstance, BaseHandler.GetJob, and BackgroundJob.Enqueue, using the AppDomain and Hangfire behavior described in the issue. Determine whether a queued job can run in its own AppDomain and document the required scope and completion criteria, including how the job's assembly references remain available during execution.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp
- Domain
- backend
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 25/100