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); }
public override async Task InvokeAsync(ClientActionContext context) { try { await Next(context).ConfigureAwait(false); } catch (Exception e) { ErrorHandlingResult result = _errorHandling.Handle(context, e); if (result == ErrorHandlingResult.Close || result == ErrorHandlingResult.Recover) { (context.Proxy as IPipelineCallback)?.ChangeState(ProxyState.Closed); } throw; } }
public override async Task InvokeAsync(ClientActionContext context) { int tries = 0; while (true) { try { await Next(context).ConfigureAwait(false); (context.Proxy as IPipelineCallback)?.ChangeState(ProxyState.Open); return; } catch (Exception e) { ErrorHandlingResult errorHandlingResult = ErrorHandling.Handle(context, e); switch (errorHandlingResult) { case ErrorHandlingResult.Close: (context.Proxy as IPipelineCallback)?.ChangeState(ProxyState.Closed); throw; case ErrorHandlingResult.Recover: if (tries >= Retries) { (context.Proxy as IPipelineCallback)?.ChangeState(ProxyState.Closed); throw; } tries++; break; case ErrorHandlingResult.Rethrow: (context.Proxy as IPipelineCallback)?.ChangeState(ProxyState.Open); throw; default: throw new ArgumentOutOfRangeException($"The value of '{errorHandlingResult}' is not supported.", nameof(errorHandlingResult)); } } context.ServerConnection = null; await Task.Delay(RetryDelay, context.RequestAborted).ConfigureAwait(false); } }
public async Task Execute_ThrowsError_Handle(bool recoverableProxy, ErrorHandlingResult handlingResult) { var pipeline = CreatePipeline( (next, ctxt) => { ctxt.ServerConnection = ConnectionDescriptor; if (ctxt.Action != ContractDescriptor.InitSession) { throw new InvalidOperationException(); } return(next(ctxt)); }); var session = pipeline.Find <SessionMiddleware>(); session.Recoverable = recoverableProxy; SetupSessionHandler("test session", true); SessionErrorHandling.Setup(r => r.Handle(It.IsAny <ClientActionContext>(), It.IsAny <Exception>())).Returns( () => { return(handlingResult); }); var proxy = CreateProxy(pipeline); await proxy.OpenSession("param"); await Assert.ThrowsAsync <InvalidOperationException>(proxy.ExecuteAsync); if (recoverableProxy) { switch (handlingResult) { case ErrorHandlingResult.Close: Assert.Equal(ProxyState.Closed, proxy.State); break; case ErrorHandlingResult.Recover: Assert.Equal(ProxyState.Ready, proxy.State); break; case ErrorHandlingResult.Rethrow: Assert.Equal(ProxyState.Open, proxy.State); break; default: throw new ArgumentOutOfRangeException(nameof(handlingResult), handlingResult, null); } } else { switch (handlingResult) { case ErrorHandlingResult.Close: Assert.Equal(ProxyState.Closed, proxy.State); break; case ErrorHandlingResult.Recover: Assert.Equal(ProxyState.Closed, proxy.State); break; case ErrorHandlingResult.Rethrow: Assert.Equal(ProxyState.Open, proxy.State); break; default: throw new ArgumentOutOfRangeException(nameof(handlingResult), handlingResult, null); } } }
public async Task Error_EnsureProperProxyState(bool retry, ErrorHandlingResult result) { var pipeline = CreatePipeline(retry ? 1 : 0); var proxy = CreateProxy(pipeline); bool called = false; Callback.Setup(c => c.Handle(It.IsAny<ClientActionContext>())).Callback<ClientActionContext>( c => { if (called) { if (result == ErrorHandlingResult.Rethrow) { throw new InvalidOperationException("This method sould not be called again."); } return; } called = true; throw new InvalidOperationException(); }).Verifiable(); ErrorHandling.Setup(e => e.Handle(It.IsAny<ClientActionContext>(), It.IsAny<Exception>())).Returns(result); if (result != ErrorHandlingResult.Recover) { await Assert.ThrowsAsync<InvalidOperationException>(() => proxy.ExecuteAsync()); } else { if (retry) { await proxy.ExecuteAsync(); } else { await Assert.ThrowsAsync<InvalidOperationException>(() => proxy.ExecuteAsync()); } } switch (result) { case ErrorHandlingResult.Close: Assert.Equal(ProxyState.Closed, proxy.State); break; case ErrorHandlingResult.Recover: if (retry) { Assert.Equal(ProxyState.Open, proxy.State); } else { Assert.Equal(ProxyState.Ready, proxy.State); } break; case ErrorHandlingResult.Rethrow: Assert.Equal(ProxyState.Open, proxy.State); break; default: throw new ArgumentOutOfRangeException(nameof(result), result, null); } }
public async Task Error_EnsureProperProxyState(bool retry, ErrorHandlingResult result) { var pipeline = CreatePipeline(retry ? 1 : 0); var proxy = CreateProxy(pipeline); bool called = false; Callback.Setup(c => c.Handle(It.IsAny <ClientActionContext>())).Callback <ClientActionContext>( c => { if (called) { if (result == ErrorHandlingResult.Rethrow) { throw new InvalidOperationException("This method sould not be called again."); } return; } called = true; throw new InvalidOperationException(); }).Verifiable(); ErrorHandling.Setup(e => e.Handle(It.IsAny <ClientActionContext>(), It.IsAny <Exception>())).Returns(result); if (result != ErrorHandlingResult.Recover) { await Assert.ThrowsAsync <InvalidOperationException>(() => proxy.ExecuteAsync()); } else { if (retry) { await proxy.ExecuteAsync(); } else { await Assert.ThrowsAsync <InvalidOperationException>(() => proxy.ExecuteAsync()); } } switch (result) { case ErrorHandlingResult.Close: Assert.Equal(ProxyState.Closed, proxy.State); break; case ErrorHandlingResult.Recover: if (retry) { Assert.Equal(ProxyState.Open, proxy.State); } else { Assert.Equal(ProxyState.Closed, proxy.State); } break; case ErrorHandlingResult.Rethrow: Assert.Equal(ProxyState.Open, proxy.State); break; default: throw new ArgumentOutOfRangeException(nameof(result), result, null); } }
public async Task Execute_ThrowsError_Handle(bool recoverableProxy, ErrorHandlingResult handlingResult) { IPipeline<ClientActionContext> pipeline = CreatePipeline( (next, ctxt) => { ctxt.ServerConnection = ConnectionDescriptor; if (ctxt.Action != ContractDescriptor.InitSession) { throw new InvalidOperationException(); } return next(ctxt); }); var session = pipeline.Find<SessionMiddleware>(); session.Recoverable = recoverableProxy; SetupSessionHandler("test session", true); SessionErrorHandling.Setup(r => r.Handle(It.IsAny<ClientActionContext>(), It.IsAny<Exception>())).Returns( () => { return handlingResult; }); var proxy = CreateProxy(pipeline); await proxy.OpenSession("param"); await Assert.ThrowsAsync<InvalidOperationException>(proxy.ExecuteAsync); if (recoverableProxy) { switch (handlingResult) { case ErrorHandlingResult.Close: Assert.Equal(ProxyState.Closed, proxy.State); break; case ErrorHandlingResult.Recover: Assert.Equal(ProxyState.Ready, proxy.State); break; case ErrorHandlingResult.Rethrow: Assert.Equal(ProxyState.Open, proxy.State); break; default: throw new ArgumentOutOfRangeException(nameof(handlingResult), handlingResult, null); } } else { switch (handlingResult) { case ErrorHandlingResult.Close: Assert.Equal(ProxyState.Closed, proxy.State); break; case ErrorHandlingResult.Recover: Assert.Equal(ProxyState.Closed, proxy.State); break; case ErrorHandlingResult.Rethrow: Assert.Equal(ProxyState.Open, proxy.State); break; default: throw new ArgumentOutOfRangeException(nameof(handlingResult), handlingResult, null); } } }