One of our legacy system has workflow implemented with
- Workflow class marked as Spring @Component
- DB insertions & workflow Start in a method marked with Spring @Transactional annotation, hoping to revert DB records incase of any exception from workflow start.
@Transactional
@Throws(CustomException::class, WorkflowNotFoundException::class)
fun startFlow(object: SomeObject, workflowId: String) {
try {
dao.createRecord(object)
val workflowOptions = WorkflowOptions.newBuilder()
.setWorkflowId(workflowId)
.setTaskQueue(taskQueue)
.build()
val workflow = workflowClient.newWorkflowStub(SampleWorkflow::class.java, workflowOptions)
WorkflowClient.start(workflow::executeTransfer, object)
return workflow
} catch (e: WorkflowNotFoundException) {
throw e
} catch (e: Exception) {
throw CustomException()
}
}
with this implementation, we noticed sometimes workflow instances are created, but without a corresponding db record. I am not sure how that can happen.
just wondering if workflowClient.start can throw an exception even if the workflow is scheduled?
p.s. we plan to modify the workflow using saga pattern & removing spring DI,
Workflow class marked as Spring @Component
Don’t think this would work well as you need to create your workflow instances via stubs.
just wondering if workflowClient.start can throw an exception even if the workflow is scheduled?
WorkflowClient.start unblocks when the execution has been created on the service.
It can throw WorkflowExecutionAlreadyStarted exception if the execution with configured workflow id is already running. Would also catch io.grpc.StatusRuntimeException for any possible gRPC errors for example service not available.
Workflow class marked as Spring @Component
Don’t think this would work well as you need to create your workflow instances via stubs.
we actually create & inject(in the above code) a spring managed instance(singleton) with stubs like:
@Bean
fun workflowClient( options: WorkflowServiceStubsOptions): WorkflowClient? {
val service = WorkflowServiceStubs.newInstance(options)
val opts = WorkflowClientOptions.newBuilder().build()
return WorkflowClient.newInstance(service, opts)
}
@Bean
fun workflowServiceStubsOptions(metricsScope: Scope): WorkflowServiceStubsOptions {
return WorkflowServiceStubsOptions.newBuilder()
.setTarget(temporalProps.serviceAddress)
.setMetricsScope(metricsScope)
.build()
}
just wondering if workflowClient.start can throw an exception even if the workflow is scheduled?
WorkflowClient.start unblocks when the execution has been created on the service.
It can throw WorkflowExecutionAlreadyStarted exception if the execution with configured workflow id is already running. Would also catch io.grpc.StatusRuntimeException for any possible gRPC errors for example service not available.
so our DB records were reverted as there was a runtime exception from start method, but workflow instance was created. I am trying to understand how this can happen.
is it possible that a workflow execution can been created on the service, even if start method throws say io.grpc.StatusRuntimeException or any other exception?
is it possible that a workflow execution can been created on the service, even if start method throws say io.grpc.StatusRuntimeException or any other exception?
Yes there are edge cases where this could be possible, your client request is a network (grpc) call to request execution. Network failures could happen after server received request and created the exec, but then response can fail.
WorkflowClient does have retries built in so this should be a common case.
Maybe for your use case write all client requests to db, also the ones that failed (maybe in separate table?) and then could have background process that validates the records in your db against whats created on the server end (for example using DescribeWorkflowExecution api).