protected virtual Exception HandleError(ClientActionContext context, Exception error, SessionMetadata session) { ErrorHandlingResult handlingResult = ErrorHandling.Handle(context, error); switch (handlingResult) { case ErrorHandlingResult.Close: session.ChangeState(context.Proxy, ProxyState.Closed); break; case ErrorHandlingResult.Recover: session.ClearSession(); session.ChangeState(context.Proxy, ProxyState.Ready); if (!Recoverable) { session.ChangeState(context.Proxy, ProxyState.Closed); } break; case ErrorHandlingResult.Rethrow: break; default: throw new ArgumentOutOfRangeException($"The value of '{handlingResult}' is not supported", nameof(handlingResult)); } return(error); }
protected virtual Exception HandleOpenConnectionError(ClientActionContext context, Exception error, SessionMetadata session) { session.ClearSession(); ErrorHandlingResult handlingResult = ErrorHandling.Handle(context, error); switch (handlingResult) { case ErrorHandlingResult.Close: session.ChangeState(context.Proxy, ProxyState.Closed); break; case ErrorHandlingResult.Recover: case ErrorHandlingResult.Rethrow: session.ChangeState(context.Proxy, ProxyState.Ready); break; default: throw new ArgumentOutOfRangeException(); } return error; }
public override async Task InvokeAsync(ClientActionContext context) { context.GetRequestOrThrow(); // access or create session assigned to current proxy SessionMetadata session = _sessions.GetOrAdd( context.Proxy, proxy => new SessionMetadata(proxy.Contract.Session)); if (session.State != ProxyState.Open) { // we need to open proxy await EnsureConnectionAsync(context, session).ConfigureAwait(false); } if (!UseDistributedSession) { // we stick to active connection otherwise new connection will be picked using PickConnectionMiddleware context.ServerConnection = session.ServerConnection; } if (context.Action.Action == session.Contract.InitSession.Action) { // at this point session is opened, assign initialization result just in case if (context.ActionResult == null) { context.ActionResult = session.InitSessionResult; } } else if (context.Action.Action == session.Contract.DestroySession.Action) { if (context.Proxy.State == ProxyState.Closed) { // no reason to continue in pipeline, proxy is already closed session.ChangeState(context.Proxy, ProxyState.Closed); context.ActionResult = session.DestroySessionResult; return; } if (context.Proxy.State == ProxyState.Ready) { // proxy was never initialized, ignore the rest of pipeline and close it context.ActionResult = session.DestroySessionResult; session.ChangeState(context.Proxy, ProxyState.Closed); return; } if (session.RequiresDestroyParameters && context.Parameters == null) { // we are trying to close proxy using IProxy.CloseAsync even when the destroy action requires actual parameters throw new BoltClientException( $"Destroing session requires parameters that were not provided for action '{context.Action.Name}'.", ClientErrorCode.InvalidDestroySessionParameters, context.Action.Name, null); } try { // execute destroy session and close proxy ClientSessionHandler.EnsureSession(context.GetRequestOrThrow(), session.SessionId); await Next(context).ConfigureAwait(false); } finally { _sessions.TryRemove(context.Proxy, out session); session.ClearSession(); session.ChangeState(context.Proxy, ProxyState.Closed); } } else { // prepare the request with session ClientSessionHandler.EnsureSession(context.GetRequestOrThrow(), session.SessionId); try { // execute pipeline await Next(context).ConfigureAwait(false); } catch (Exception e) { Exception handled = HandleError(context, e, session); if (e == handled) { // the handled error is same, so just rethrow throw; } if (handled != null) { throw handled; } } } }