Dependency Injection to Workflows

Other threads have covered this topic before, but seem to end with Maxim asking “what is your specific use case” and then no response.

I have a particular use case. Our frameworks team has three observability platforms: plain logging, metrics, and also “structured logging” that stores to snowflake. Workflows support the first two use cases by Workflow.logger and Workflow.getMetricsScope, but there’s nothing for the third use case.

Our e.g. “StructuredLogsWriter” is set up at app startup time and the only way to access it is via guice dependency injection. Yes we could write a “StructuredLogsActivity”, inject StructuredLogsWriter there, and use that Activity to write structured logs from workflows. But that adds undesirable latency overhead and limits when, where, and how much we can do this.

Ideally we’d just be able to inject a StructuredLogsWriter into the workflow implementations and have it work–even if we have to put WorkflowUnsafe.isReplaying checks everywhere.

It sounds like Temporal has been pretty consistent over the years on the policy of not allowing DI in workflows. But I think there are valid use cases to allow it. This way you can also get rid of the logging and metrics-specific configuration APIs mentioned above.

Granted, doing this does provide more opportunity for people to shoot themselves in the foot, if they don’t remember to hide it all by WorkflowUnsafe.isReplaying checks. But perhaps that could just go into docs? Or make the attribute name e.g. @InjectUnsafe? Is there any technical reason that injecting into workflows is not allowed, or is it mainly to prevent users from misunderstanding how workflows are supposed to be designed and/or inadvertently adopting bad patterns incompatible with Temporal design?

Or is my use case actually one of these bad patterns?

Your use case is reasonable. You can implement it through an interceptor. As the interceptor instance is configured with the worker you can inject your StructuredLogsWriter into it. Then you can store it in a static variable of WorkflowLocal type and access it through a static method.