Best Practices for Service Lifecycles and Dependency Injection (Executors/Workflows) #1717
-
|
Hello there! This framework seems really promising. I'm currently integrating it into a microservice that continuously processes messages from an event queue and I have some questions about the idiomatic way to handle service setup and lifecycle. I've registered my executors and workflow as singletons, like so: builder.Services.AddSingleton<IChatClientFactory, ChatClientFactory>();
builder.Services.AddSingleton(sp =>
sp.GetRequiredService<IChatClientFactory>().CreateClient());
builder.Services.AddSingleton<StartExecutor>();
builder.Services.AddSingleton<TransformExecutor>();
builder.Services.AddSingleton<OptimistExecutor>();
builder.Services.AddSingleton<CynicExecutor>();
builder.Services.AddSingleton<AnalysisAggregatorExecutor>();
builder.Services.AddSingleton<IWorkflowFactory, WorkflowFactory>();
builder.Services.AddSingleton(sp =>
sp.GetRequiredService<IWorkflowFactory>().CreateWorkflow());This approach works well, provided I keep the executors stateless and rely on the context for state management. My questions are:
Thank you! |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 1 reply
-
|
Assuming that your executors are stateless, singletons are probably a good way of managing them. For "pure" function executors (input => output, no side-effects), this is almost certainly the case. Once you start thinking about state it becomes a little more complicated and depends a little on what concurrency mode you intend to use when executing the workflow. To allow developers to begin quickly with minimal boilerplate, we allow them to pass Executor instances directly to the To protect against this, we introduced first the ability to run Workflows serially across multiple runs by letting Executors implement a "reset" protocol using What this means for hosting in DI:
One last thing to note: By default, using the |
Beta Was this translation helpful? Give feedback.
Assuming that your executors are stateless, singletons are probably a good way of managing them. For "pure" function executors (input => output, no side-effects), this is almost certainly the case.
Once you start thinking about state it becomes a little more complicated and depends a little on what concurrency mode you intend to use when executing the workflow. To allow developers to begin quickly with minimal boilerplate, we allow them to pass Executor instances directly to the
WorkflowBuilder. If those instances contain state on the object, however, it could cause bad behaviour if used simultaneously from multiple threads or multiple concurrent runs.To protect against this, we introduc…