Skip to content

Commit

Permalink
Handle SaveState correctly when an actor method throws an exception. (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
amanbha committed Oct 10, 2019
1 parent 93d2da8 commit 8782b91
Show file tree
Hide file tree
Showing 3 changed files with 14 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,11 @@ public static void AddActorMethodRoute(this IRouteBuilder routeBuilder)
}
catch (Exception e)
{
context.Response.Headers.Add("Connection: close", default(string));
context.Response.ContentType = "application/json";
context.Response.StatusCode = StatusCodes.Status500InternalServerError;
await context.Response.WriteAsync(e.ToString());
await context.Response.CompleteAsync();
context.Response.Headers.Add("Connection: close", string.Empty);
}
}
});
Expand Down
21 changes: 10 additions & 11 deletions src/Microsoft.Dapr.Actors/Runtime/Actor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,14 +93,10 @@ internal async Task OnPostActorMethodAsyncInternal(ActorMethodContext actorMetho
await this.SaveStateAsync();
}

internal void OnInvokeFailed()
internal Task OnInvokeFailedAsync()
{
this.IsDirty = true;
}

internal Task ResetStateAsync()
{
return this.StateManager.ClearCacheAsync();
// Exception has been thrown by user code, reset the state in state manager.
return this.ResetStateAsync();
}

internal Task FireTimerAsync(string timerName)
Expand All @@ -109,6 +105,12 @@ internal Task FireTimerAsync(string timerName)
return timer.AsyncCallback.Invoke(timer.State);
}

internal Task ResetStateAsync()
{
// Exception has been thrown by user code, reset the state in state manager.
return this.StateManager.ClearCacheAsync();
}

/// <summary>
/// Saves all the state changes (add/update/remove) that were made since last call to
/// <see cref="Actor.SaveStateAsync"/>,
Expand All @@ -117,10 +119,7 @@ internal Task FireTimerAsync(string timerName)
/// <returns>A task that represents the asynchronous save operation.</returns>
protected async Task SaveStateAsync()
{
if (!this.IsDirty)
{
await this.StateManager.SaveStateAsync();
}
await this.StateManager.SaveStateAsync();
}

/// <summary>
Expand Down
4 changes: 3 additions & 1 deletion src/Microsoft.Dapr.Actors/Runtime/ActorManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -239,11 +239,13 @@ private async Task<T> DispatchInternalAsync<T>(ActorId actorId, ActorMethodConte
// invoke the function of the actor
await actor.OnPreActorMethodAsyncInternal(actorMethodContext);
retval = await actorFunc.Invoke(actor, cancellationToken);

// PostActivate will save the state, its not invoked when actorFunc invocation throws.
await actor.OnPostActorMethodAsyncInternal(actorMethodContext);
}
catch (Exception ex)
{
actor.OnInvokeFailed();
await actor.OnInvokeFailedAsync();
ActorTrace.Instance.WriteError(TraceType, $"Got exception from actor method invocation: {ex}");
throw;
}
Expand Down

0 comments on commit 8782b91

Please sign in to comment.