问题
My objective is to run a never ending process in a parallel thread. The problem is, I cannot just instantiate my worker service in the new Thread, because I am using DI in my application.
Based on my research here on SO, I have noticed many people are suggesting that Abstract Factories need to be injected into the thread to dynamically instantiate a thread-safe object in a parallel thread. 1, 2
/// <summary>
/// Responsible for starting parallel long running worker threads
/// </summary>
public class ParallelWorkerStarter
{
private readonly IQueueProcessorFactory _queueProcessorFactory;
public ParallelWorkerStarter(IQueueProcessorFactory queueProcessorFactory)
{
_queueProcessorFactory = queueProcessorFactory;
}
public void StartQueueProcessorThread()
{
queueProcessor = new Thread(
() =>
{
_queueProcessorFactory.Create().ProcessQueue();
})
{ Name = "QueueProcessor" };
queueProcessor.Start();
}
}
The Abstract Factory for IQueueProcessorFactory
looks like this:
/// <summary>
/// Abstract factory responsible for producing an <see cref="IQueueProcessor"/>
/// </summary>
/// <remarks>
/// This abstract factory is used to generate an <see cref="IQueueProcessor"/> In a seperate thread.
/// Therefore, all of its dependencies also need to be dynamically generated
/// </remarks>
public interface IQueueProcessorFactory
{
/// <summary>
/// Dynamically creates ab <see cref="IQueueProcessor"/>
/// </summary>
/// <returns>
/// The <see cref="IQueueProcessor"/>.
/// </returns>
IQueueProcessor Create();
}
Now, my main problem is, the concrete QueueProcessor
that implements IQueueProcessor
has 11 dependencies (I'm aware of the SRP code smell), and each dependency has 5-6 dependencies itself.
/// <inheritdoc />
public class QueueProcessorFactory : IQueueProcessorFactory
{
private readonly IEventTriggerQueuedEventServiceFactory _qeueuedEventServiceFactory;
private readonly ILoggerFactory _loggerFactory;
private readonly IEventTriggerActionGroupLogServiceFactory _eventTriggerActionGroupLogServiceFactory;
private readonly IExceptionLogServiceFactory _exceptionLogServiceFactory;
private readonly IEventTriggerServiceFactory _eventTriggerServiceFactory;
private readonly IConditionServiceFactory _conditionServiceFactory;
private readonly IEventTriggerActionServiceFactory _eventTriggerActionServiceFactory;
private readonly IEngineEnabledCheckerFactory _engineEnabledCheckerFactory;
private readonly IEventTriggerScheduleSetServiceFactory _eventTriggerScheduleSetServiceFactory;
private readonly IEventTriggerActionResultServiceFactory _eventTriggerActionResultServiceFactory;
private readonly IWorkflowExceptionHandlerFactory _workflowExceptionHandlerFactory;
public QueueProcessorFactory(
IEventTriggerQueuedEventServiceFactory qeueuedEventServiceFactory,
ILoggerFactory loggerFactory,
IEventTriggerActionGroupLogServiceFactory eventTriggerActionGroupLogServiceFactory,
IExceptionLogServiceFactory exceptionLogServiceFactory,
IEventTriggerServiceFactory eventTriggerServiceFactory,
IConditionServiceFactory conditionServiceFactory,
IEventTriggerActionServiceFactory eventTriggerActionServiceFactory,
IEngineEnabledCheckerFactory engineEnabledCheckerFactory,
IEventTriggerScheduleSetServiceFactory eventTriggerScheduleSetServiceFactory,
IEventTriggerActionResultServiceFactory eventTriggerActionResultServiceFactory,
IWorkflowExceptionHandlerFactory workflowExceptionHandlerFactory)
{
_qeueuedEventServiceFactory = qeueuedEventServiceFactory;
_loggerFactory = loggerFactory;
_eventTriggerActionGroupLogServiceFactory = eventTriggerActionGroupLogServiceFactory;
_exceptionLogServiceFactory = exceptionLogServiceFactory;
_eventTriggerServiceFactory = eventTriggerServiceFactory;
_conditionServiceFactory = conditionServiceFactory;
_eventTriggerActionServiceFactory = eventTriggerActionServiceFactory;
_engineEnabledCheckerFactory = engineEnabledCheckerFactory;
_eventTriggerScheduleSetServiceFactory = eventTriggerScheduleSetServiceFactory;
_eventTriggerActionResultServiceFactory = eventTriggerActionResultServiceFactory;
_workflowExceptionHandlerFactory = workflowExceptionHandlerFactory;
}
/// <inheritdoc />
public IQueueProcessor Create()
{
return new QueueProcessor(
_qeueuedEventServiceFactory.Create(),
_loggerFactory.Create(),
_eventTriggerActionGroupLogServiceFactory.Create(),
_exceptionLogServiceFactory.Create(),
_eventTriggerServiceFactory.Create(),
_conditionServiceFactory.Create(),
_eventTriggerActionServiceFactory.Create(),
_engineEnabledCheckerFactory.Create(),
_eventTriggerScheduleSetServiceFactory.Create(),
_eventTriggerActionResultServiceFactory.Create(),
_workflowExceptionHandlerFactory.Create());
}
}
Does this mean I need ~60+ abstract factories in order to instantiate my IQueueProcessor
in a worker thread? This sounds like a nightmare! Is there a better way or a more efficient way to achieve this?
回答1:
Does this mean I need ~60+ abstract factories in order to instantiate my
IQueueProcessor
in a worker thread?
In the worst case, that may be required. This can happen when all dependencies must have Transient lifetime - for example when they aren't thread-safe.
In the best case, however, all those dependencies could have Singleton lifetime, which could be appropriate for thread-safe dependencies. In that case, no internal factories are required:
public class QueueProcessorFactory : IQueueProcessorFactory
{
private readonly IEventTriggerQueuedEventService _qeueuedEventService;
private readonly ILogger _logger;
private readonly IEventTriggerActionGroupLogService _eventTriggerActionGroupLogService;
// etc...
public QueueProcessorFactory(
IEventTriggerQueuedEventService qeueuedEventService,
ILogger logger,
IEventTriggerActionGroupLogService eventTriggerActionGroupLogService,
/* etc... */)
{
_qeueuedEventService = qeueuedEventService;
_logger = logger;
_eventTriggerActionGroupLogService = eventTriggerActionGroupLogService;
// etc...
}
public IQueueProcessor Create()
{
return new QueueProcessor(
_qeueuedEventService,
_logger,
_eventTriggerActionGroupLogService,
/* etc... */);
}
}
In reality, you may need to mix some Transient dependencies (that'd require factories) with some Singleton dependencies.
If you ultimately require dozens of factories, you could consider using a DI Container. Some of them can automatically generate implementations of factory interfaces - you only have to supply the interface they must implement.
Additionally, you don't have to define an interface for each dependency, but could consider instead using a generic interface like:
public interface IFactory<T>
{
T Create();
}
Again, some of the DI Containers out there support such factories. You could also consider entirely dispensing with an interface and just use a delegate like Func<T>
.
Unless the circumstances are special, however, I don't recommend a DI Container, but rather endorse Pure DI. When you use a DI Container, you lose compile-time safety, which I tend to think isn't worth the trade-off; after all, the bottleneck of programming is rarely your typing speed.
来源:https://stackoverflow.com/questions/50137520/instantiating-an-object-in-a-worker-thread-with-dependency-injection