This is how I register the jobs:
public static void Register(string jobSchedule)
{
RecurringJob.AddOrUpdate(
“O365SubscriptionSyncJob” + Sites.Canada,
j => j.Execute(),
jobSchedule,
queue: Queues.Canada);
RecurringJob.AddOrUpdate<O365SubscriptionSyncJobUS>(
"O365SubscriptionSyncJob" + Sites.UnitedStates,
j => j.Execute(),
jobSchedule,
queue: Queues.UnitedStates);
RecurringJob.AddOrUpdate<O365SubscriptionSyncJobEU>(
"O365SubscriptionSyncJob" + Sites.Europe,
j => j.Execute(),
jobSchedule,
queue: Queues.Europe);
}
This is one job:
[Site(Sites.Canada)]
public class O365SubscriptionSyncJobCA : IJob
{
private readonly O365SubscriptionSyncJob _o365SubscriptionSyncJob;
public O365SubscriptionSyncJobCA(O365SubscriptionSyncJob o365SubscriptionSyncJob)
{
this._o365SubscriptionSyncJob = o365SubscriptionSyncJob;
}
[DisableConcurrentExecution(0)]
[AutomaticRetry(Attempts = 0, LogEvents = false)]
public void Execute()
{
this._o365SubscriptionSyncJob.Execute();
}
}
Custom StructureMap stuff:
using System;
using System.Reflection;
using System.Threading;
using Hangfire;
using StructureMap;
using Core.O365.Entities.Platform;
using Core.O365.Entities.Platform.Organizations;
using Core.O365.Repositories.Factories;
using Core.O365.Repositories.Gateways.Subscriptions;
using Core.O365.Services.Subscriptions;
using Validation;
namespace Core.O365.Front.WebApi.HangfireJobs
{
// Source: https://github.com/cocowalla/Hangfire.StructureMap/edit/master/src/Hangfire.StructureMap/StructureMapJobActivator.cs
public class StructureMapJobActivator : JobActivator
{
private readonly IContainer _container;
public StructureMapJobActivator(IContainer container)
{
this._container = Validate.Is.Not.Null(container, nameof(container));
}
public override object ActivateJob(Type jobType)
{
throw new NotImplementedException("Contact Ben if this is called");
}
public override JobActivatorScope BeginScope(JobActivatorContext context)
{
return new StructureMapDependencyScope(this._container.GetNestedContainer(), this._container);
}
private class StructureMapDependencyScope : JobActivatorScope
{
private readonly IContainer _container;
private readonly IContainer _parentContainer;
public StructureMapDependencyScope(IContainer container, IContainer parentContainer)
{
this._container = container;
this._parentContainer = parentContainer;
}
public override object Resolve(Type type)
{
this.ConfigureSiteScopedDependencies(type.GetCustomAttribute<SiteAttribute>()?.Value);
return this._container.GetInstance(type);
}
public override void DisposeScope()
{
this._container.Dispose();
}
private void ConfigureSiteScopedDependencies(string siteCode)
{
if (siteCode == null)
{
return;
}
this._container.Configure(
x =>
{
x.For<IRepositoryFactory>()
.HybridHttpOrThreadLocalScoped()
.Use(y => y.GetInstance<IRepositoryFactory>(siteCode.ToUpper()));
x.For<IOrganizationSiteScopedRepository>()
.HybridHttpOrThreadLocalScoped()
.Use(y => y.GetInstance<IOrganizationSiteScopedRepository>(siteCode.ToUpper()));
x.For<ISubscriptionImportService>()
.HybridHttpOrThreadLocalScoped()
.Use(y => y.GetInstance<ISubscriptionImportService>(siteCode.ToUpper()));
});
var subscriptionGateway = this._container.GetInstance<ISubscriptionGateway>();
var site = subscriptionGateway.Site;
if (Sites.Parse(site) != siteCode)
{
/// IoC problem, thread reused!
}
}
}
}
}