Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 17 additions & 7 deletions src/Temporalio/Client/TemporalClient.Workflow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -253,19 +253,29 @@ public override async Task<WorkflowUpdateHandle<TUpdateResult>> StartUpdateWithS
}
catch (Exception e)
{
// If this is a multi-operation failure, set exception to the first non-aborted
// If this is a multi-operation failure, set exception to the first present,
// non-OK, non-aborted error
if (e is RpcException rpcErr)
{
var status = rpcErr.GrpcStatus.Value;
if (status != null && status.Details.Count == 1)
{
if (status.Details[0].TryUnpack(out Api.ErrorDetails.V1.MultiOperationExecutionFailure failure))
{
var nonAborted = failure.Statuses.FirstOrDefault(s => s.Details.Count == 0 ||
!s.Details[0].Is(Api.Failure.V1.MultiOperationExecutionAborted.Descriptor));
var grpcStatus = new GrpcStatus() { Code = nonAborted.Code, Message = nonAborted.Message };
grpcStatus.Details.AddRange(nonAborted.Details);
e = new RpcException(grpcStatus);
var nonAborted = failure.Statuses.FirstOrDefault(s =>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

variable name could be failureStatus or something, but not blocking.

// Exists
s != null &&
// Not ok
s.Code != (int)RpcException.StatusCode.OK &&
// Not aborted
(s.Details.Count == 0 ||
!s.Details[0].Is(Api.Failure.V1.MultiOperationExecutionAborted.Descriptor)));
if (nonAborted != null)
{
var grpcStatus = new GrpcStatus() { Code = nonAborted.Code, Message = nonAborted.Message };
grpcStatus.Details.AddRange(nonAborted.Details);
e = new RpcException(grpcStatus);
}
}
}
}
Expand Down Expand Up @@ -462,7 +472,7 @@ public async override Task<WorkflowUpdateHandle<TResult>> StartWorkflowUpdateAsy
// If the requested stage is completed, wait for result, but discard the update
// exception, that will come when _they_ call get result
var handle = new WorkflowUpdateHandle<TResult>(
Client, req.Request.Meta.UpdateId, input.Id, input.RunId)
Client, req.Request.Meta.UpdateId, input.Id, resp.UpdateRef.WorkflowExecution.RunId)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should really add a test for this. (I know the other fix is hard to test).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added assertion to existing test that would have failed before (basically just ensures run ID now exists, because it was null before)

{ KnownOutcome = resp.Outcome };
if (input.Options.WaitForStage == WorkflowUpdateStage.Completed)
{
Expand Down
9 changes: 6 additions & 3 deletions tests/Temporalio.Tests/Worker/WorkflowWorkerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3697,10 +3697,13 @@ await ExecuteWorkerAsync<UpdateWorkflow>(async worker =>
(UpdateWorkflow wf) => wf.RunAsync(),
new(id: $"workflow-{Guid.NewGuid()}", taskQueue: worker.Options.TaskQueue!));

// Make all possible overload calls via start then get response
await (await ((WorkflowHandle)handle).StartUpdateAsync(
// Make all possible overload calls via start then get response. For
// the first update we'll also confirm the run ID is set.
var updateHandle = await ((WorkflowHandle)handle).StartUpdateAsync(
(UpdateWorkflow wf) => wf.DoUpdateNoParamNoResponseAsync(),
new(WorkflowUpdateStage.Accepted))).GetResultAsync();
new(WorkflowUpdateStage.Accepted));
Assert.NotNull(updateHandle.WorkflowRunId);
await updateHandle.GetResultAsync();
Assert.Equal(
$"no-param-response: {handle.Id}",
await (await ((WorkflowHandle)handle).StartUpdateAsync(
Expand Down
Loading