elsa-workflows / elsa-core

A .NET workflows library
https://v3.elsaworkflows.io/
MIT License
6.05k stars 1.1k forks source link

DispatchPendingWorkflowAsync method returns NullReferenceException #2959

Open stanroxana opened 2 years ago

stanroxana commented 2 years ago

Elsa version : 2.6.0

Hello,

Excuse me for the long post that's coming. I've been trying to use the method DispatchPendingWorkflowAsync and CollectAndExecuteWorkflowsAsync from the workflow launchpad service. I am running 2 simple workflows (as in starting one -> it finishes; starting the second -> it finishes; and so on in random order) For every of these 2 workflows I have a bookmark that gets executed in my code by calling the method CollectAndExecuteWorkflowsAsync.

First thing I observed after the method CollectAndExecuteWorkflowsAsync is called is that sometimes it created another new instance of the other workflow. All other instances were in status 2 - finished, no other workflow in pending. So if I started workflow 1 -> CollectAndExecuteWorkflowsAsync is called -> CollectedWorkflows result gives 2 workflows (an instance for workflow 1 and a new instance for workflow 2) -> workflow 1 finished and a new instance with workflow 2 is created This is the code that I executed:

var templateMessageContext = new WorkflowsQuery(nameof(SendMessage), new SendTemplateMessageBookmark(), workflowInstance.CorrelationId, workflowInstance.Id);
var templateMessageWorkflowInput = new WorkflowInput(message);
var collectedWorkflow = await _workflowLaunchpad.CollectAndExecuteWorkflowsAsync(templateMessageContext, templateMessageWorkflowInput, cancellationToken);

So after this, I started looking into the launchpad service and I tested a similar method, DispatchPendingWorkflowAsync:

var collectedWorkflow = new CollectedWorkflow(workflowInstance.Id, null);
await _workflowLaunchpad.DispatchPendingWorkflowAsync(collectedWorkflow, templateMessageWorkflowInput, cancellationToken);

then I received this exception at execution:

 ---> (Inner Exception #1) System.NullReferenceException: Object reference not set to an instance of an object.
   at Elsa.Services.Workflows.WorkflowRunner.ResumeWorkflowAsync(WorkflowExecutionContext workflowExecutionContext, IActivityBlueprint activity, CancellationToken cancellationToken)
   at Elsa.Services.Workflows.WorkflowRunner.RunWorkflowInternalAsync(WorkflowExecutionContext workflowExecutionContext, String activityId, CancellationToken cancellationToken)
   at Elsa.Services.Workflows.WorkflowRunner.RunWorkflowAsync(IWorkflowBlueprint workflowBlueprint, WorkflowInstance workflowInstance, String activityId, WorkflowInput input, CancellationToken cancellationToken)
   at Elsa.Services.Workflows.WorkflowResumer.ResumeWorkflowAsync(WorkflowInstance workflowInstance, String activityId, WorkflowInput input, CancellationToken cancellationToken)
   at Elsa.Services.Workflows.WorkflowInstanceExecutor.ExecuteAsync(WorkflowInstance workflowInstance, String activityId, WorkflowInput input, CancellationToken cancellationToken)
   at Elsa.Decorators.LockingWorkflowInstanceExecutor.ExecuteAsync(String workflowInstanceId, String activityId, WorkflowInput input, CancellationToken cancellationToken)
   at Elsa.Decorators.LockingWorkflowInstanceExecutor.ExecuteAsync(String workflowInstanceId, String activityId, WorkflowInput input, CancellationToken cancellationToken)
   at Elsa.Decorators.LockingWorkflowInstanceExecutor.ExecuteAsync(String workflowInstanceId, String activityId, WorkflowInput input, CancellationToken cancellationToken)
   at Elsa.Services.Dispatch.Consumers.ExecuteWorkflowInstanceRequestConsumer.Handle(ExecuteWorkflowInstanceRequest message)
   at Rebus.Pipeline.Receive.HandlerInvoker`1.Invoke()
   at Rebus.Pipeline.Receive.DispatchIncomingMessageStep.Process(IncomingStepContext context, Func`1 next)
   at Rebus.Sagas.LoadSagaDataStep.Process(IncomingStepContext context, Func`1 next)
   at Rebus.Pipeline.Receive.ActivateHandlersStep.Process(IncomingStepContext context, Func`1 next)
   at Rebus.Pipeline.Receive.HandleRoutingSlipsStep.Process(IncomingStepContext context, Func`1 next)
   at Rebus.Pipeline.Receive.DeserializeIncomingMessageStep.Process(IncomingStepContext context, Func`1 next)
   at Rebus.DataBus.ClaimCheck.HydrateIncomingMessageStep.Process(IncomingStepContext context, Func`1 next)
   at Rebus.Pipeline.Receive.HandleDeferredMessagesStep.Process(IncomingStepContext context, Func`1 next)
   at Rebus.Retry.FailFast.FailFastStep.Process(IncomingStepContext context, Func`1 next)
   at Rebus.Retry.Simple.SimpleRetryStrategyStep.DispatchWithTrackerIdentifier(Func`1 next, String identifierToTrackMessageBy, ITransactionContext transactionContext, String messageId, String secondLevelMessageId)<---

I've been trying some debugging on it and the method _workflowInstanceDispatcher.DispatchAsync is giving the error.

Second observation (but maybe I'm wrong), I see that in Elsa 2.6.0 the CollectedWorkflow constructor has only 2 arguments. In the workflow launchpad service, CollectedWorkflow has 3 arguments.

Regardless of my untrained observations, could you please guide me towards some solution of this problem? Let me know if you need more information.

Thank you !!

sfmskywalker commented 2 years ago

Hi @stanroxana ,

Depending on what your workflow contains, it is entirely possible to sometimes get a new workflow instance and other times not. If your workflow starts with a trigger for example, and you invoke this workflow yourself, it will create a new instance. The second time, it will resume this instance and not create a new one. It also depends on whether or not you are providing correlation IDs.

If it is indeed the case that your workflows start with a trigger (such as Timer, Signal Received, HTTP Endpoint etc.) then you should not invoke these workflows yourself, but instead let Elsa trigger these for you.

With regards to the unhandled exception could you share your (simplified) project with me that I can look at?

stanroxana commented 2 years ago

@sfmskywalker

Thank you for the response. To clarify, in short, what you were wondering: the workflow starts with a custom activity (that is not implemented as or derived from Timer, Signal Received, HTTP Endpoint, but is more like a console write activity).

In the meantime, I have debugged the problem locally, in the (Elsa) library and the workaround I found was to provide the (blocking) activity ID as well, to the method DispatchPendingWorkflowAsync. (this makes the instance creation and the exception not happen anymore)

Regarding the exception, I can put together a simplified project were this error reproduces, as soon as I can. Can you tell me where should I send you the project?

Thank you and have a great day!