// TODO handle timeout? TimeoutException on this task, and finish preparation in the background and set idle at the end, problem: it shouldn't know about idle! // Can be called only after a successful WaitIdleAsync()! private async Task PrepareInstanceAsync() { if (instance != null && instance.WorkflowInstanceState == WorkflowInstanceState.Aborted) { // We try to restart or reload it from the previous persisted state. await grain.LoadWorkflowStateAsync(); instance = null; } if (instance == null) { IWorkflowState workflowState = grain.WorkflowState; if (workflowState.InstanceValues == null) { // Start, there is no previous persisted state. instance = new WorkflowInstance(this, workflowDefinitionFactory(workflowDefinitionIdentity), workflowDefinitionIdentity); instance.Start(await grain.OnStartAsync(), GetExtensions()); } else { // Load previous persisted state. instance = new WorkflowInstance(this, workflowDefinitionFactory(workflowState.WorkflowDefinitionIdentity), workflowState.WorkflowDefinitionIdentity); // TODO If workflowState.WorkflowDefinitionIdentity differs from workflowDefinitionIdentity, we should create a DynamicUpdateMap and update the loaded instance. // Currently we downgrade the workflowDefinitionIdentity to the loaded value. // NOTE The workflowDefinitionFactory usually yields the same singleton workflow definition (ie. activity) for the same WorkflowDefinitionIdentity, // what happens with these activity trees during update??? // await instance.LoadAsync(workflowState.InstanceValues, GetExtensions(), >>>DynamicUpdateMap: workflowState.WorkflowDefinitionIdentity -> workflowDefinitionIdentity<<<); await instance.LoadAsync(workflowState.InstanceValues, GetExtensions()); workflowDefinitionIdentity = workflowState.WorkflowDefinitionIdentity; } } if (instance.WorkflowInstanceState == WorkflowInstanceState.Runnable) { TaskCompletionSource <object> taskCompletionSource = new TaskCompletionSource <object>(); await RunInstanceWithActiveTaskCompletionSourceProtectionAsync(taskCompletionSource, ActiveTaskCompletionSource.ProtectionLevel.UnhandledExceptionAndNormalCompletion); await taskCompletionSource.Task; } }
// TODO handle timeout? TimeoutException on this task, and finish preparation in the background and set idle at the end, problem: it shouldn't know about idle! // Can be called only after a successful WaitIdleAsync()! private async Task PrepareAsync() { if (completionState == null) { if (instance != null && instance.WorkflowInstanceState == WorkflowInstanceState.Aborted) { // We try to restart or reload it from the previous persisted state. await grain.LoadWorkflowStateAsync(); instance = null; } if (instance == null) { IWorkflowState workflowState = grain.WorkflowState; WorkflowIdentity workflowDefinitionIdentity = null; IWorkflowInstance instance = null; WorkflowCompletionState completionState = null; if (workflowState.InstanceValues == null) { // Start, there is no previous persisted state. workflowDefinitionIdentity = workflowDefinitionIdentityFactory(); instance = new WorkflowInstance(this, workflowDefinitionFactory(workflowDefinitionIdentity), workflowDefinitionIdentity); instance.Start(await RaiseStartingAsync(), Extensions); } else if (!WorkflowInstance.IsCompleted(workflowState.InstanceValues)) { // Load previous persisted state. instance = new WorkflowInstance(this, workflowDefinitionFactory(workflowState.WorkflowDefinitionIdentity), workflowState.WorkflowDefinitionIdentity); // TODO If workflowState.WorkflowDefinitionIdentity differs from workflowDefinitionIdentity, we should create a DynamicUpdateMap and update the loaded instance. // Currently we downgrade the workflowDefinitionIdentity to the loaded value. // NOTE The workflowDefinitionFactory usually yields the same singleton workflow definition (ie. activity) for the same WorkflowDefinitionIdentity, // what happens with these activity trees during update??? // await instance.LoadAsync(workflowState.InstanceValues, GetExtensions(), >>>DynamicUpdateMap: workflowState.WorkflowDefinitionIdentity -> workflowDefinitionIdentity<<<); await instance.LoadAsync(workflowState.InstanceValues, Extensions); workflowDefinitionIdentity = workflowState.WorkflowDefinitionIdentity; } else { completionState = new WorkflowCompletionState(); await completionState.LoadAsync(workflowState.InstanceValues, HostExtensions, Parameters); } // Set the the values only, when the instance/completionState was successfully initialized. this.workflowDefinitionIdentity = workflowDefinitionIdentity; this.instance = instance; this.completionState = completionState; } if (instance != null && instance.WorkflowInstanceState == WorkflowInstanceState.Runnable) { TaskCompletionSource <object> taskCompletionSource = new TaskCompletionSource <object>(); try { activeTaskCompletionSources.ProtectionLevel = ActiveTaskCompletionSources.TaskCompletionSourceProtectionLevel.Preparation; activeTaskCompletionSources.Add(taskCompletionSource); await instance.RunAsync(); await taskCompletionSource.Task; } finally { activeTaskCompletionSources.ProtectionLevel = ActiveTaskCompletionSources.TaskCompletionSourceProtectionLevel.Normal; activeTaskCompletionSources.Remove(taskCompletionSource); } } } }