Dependency Injection: Converting existing DI code to work with Temporal

Hi All,

I was trying to convert some of our existing code to work with Temporal and run into a dead-end when needing to deal with Dependency Injection.

Our code is a ASP.NET Core web API with various [injected] services that interact with each other either on the same instance or on remote instances.

I understand that writing workflows with dependency injection is discouraged due to determinism requirements.

The question is how would I go about converting existing DI code into a workflow?

I’m using the dotnet-sdk alpha release.

Thanks.

1 Like

You do inject the dependent services into activity implementations.

1 Like

Thanks for the response but something is still unclear to me.
Many of my dependencies are Scoped Services. I’m not sure that simply injecting these to the activity class will retain their scope.

I’ll try to clarify (hopefully) with an example:
My original implementation without temporal is similar to this:

// Original flow without temporal

//.....
using (var scope = serviceProvider.CreateScope())
{
	var happyService = scope.ServiceProvider.GetRequiredService<IMyHappyService>();
	var funService = await scope.ServiceProvider.GetRequiredService<IMyFunService>();

	await happyService.BeHappyAsync(tenantId);

	var jollyService = scope.ServiceProvider.GetRequiredService<IMyJollyService>();
	await jollyService.DoJollyThingsAsync();

	await funService.HaveFunAsync();
}

Now I would like to transform this flow to work with Temporal, where the 3 awaited statements would be the activities of this flow. From my understanding the new implementation would be something like the following (some part omitted for brevity):

// New Temporal-supported flow
//.....
using (var scope = serviceProvider.CreateScope())
{
	await temporalClient.ExecuteWorkflowAsync(MyWorkflow.Ref.RunAsync,
                        new List<string>(),
                        new WorkflowOptions($"Some Id", "Some Queue Name"));
}

//...
[Workflow("Some Workflow Name")]
public class MyWorkflow
{
	// Understand the reason for this pattern
	public static MyWorkflow Ref = WorkflowRefs.Create<MyWorkflow>();

	private readonly ActivityOptions _options = new() 
	{ 
		// ...
	};

	[WorkflowRun]
	public async Task RunAsync()
	{
		await Workflow.ExecuteActivityAsync(
			"Be Happy Activity",
			new List<object>(),
			_options);

		await Workflow.ExecuteActivityAsync(
			"Do Jolly Things Activity",
			new List<object>(),
			_options);

		await workflow.ExecuteActivityAsync(
		    "Have Fun Activity",
		    new List<object>(),
		    _options);
	}
}

// Need to inject scoped services here
public class TenantCreationActivities
{
	private readonly IMyHappyService _happyService;
	private readonly IMyFunService _funService;
	private readonly IMyJollyService _jollyService;

	public TenantCreationActivities(
		IMyHappyService happyService,
		IMyFunService funService,
		IMyJollyService jollyService
		)
	{
		_happyService = happyService;
		_funService = funService;
		_jollyService = jollyService;
	}

	[Activity("Be Happy Activity")]
	public async Task HappyActivity()
	{
		await happyService.BeHappyAsync();
	}

	[Activity("Do Jolly Things Activity")]
	public async Task JollyActivity()
	{
		await jollyService.DoJollyThingsAsync();
	}

	[Activity("Have Fun Activity")]
	public async Task FunActivity()
	{
		await funService.HaveFunAsync();
	}
}

Is this indeed the expected way to use scoped dependencies when building a Temporal workflow?
If not any guidance will be appreciated.

1 Like