public override async Task OpenAsync(bool explicitOpen, CancellationToken cancellationToken) { TaskCompletionSource <int> openCompletionBeforeOperationStarted = Volatile.Read(ref this.openCompletion); if (openCompletionBeforeOperationStarted == null) { openCompletionBeforeOperationStarted = new TaskCompletionSource <int>(); TaskCompletionSource <int> currentOpenPromise; if ((currentOpenPromise = Interlocked.CompareExchange(ref this.openCompletion, openCompletionBeforeOperationStarted, null)) == null) { IDelegatingHandler handlerBeforeOperationStarted = this.ContinuationFactory(Context); this.InnerHandler = handlerBeforeOperationStarted; try { await this.ExecuteWithErrorHandlingAsync(() => base.OpenAsync(explicitOpen, cancellationToken), false, cancellationToken); openCompletionBeforeOperationStarted.TrySetResult(0); } catch (Exception ex) when(IsTransportHandlerStillUsable(ex)) { this.Reset(openCompletionBeforeOperationStarted, handlerBeforeOperationStarted); throw; } catch (Exception ex) when(!ex.IsFatal()) { throw; } } else { await currentOpenPromise.Task; } } else { await openCompletionBeforeOperationStarted.Task; } }
// Tests_SRS_DEVICECLIENT_33_001: [** If the given eventMessageInternal argument is null, fail silently **]** public async Task ModuleClient_OnReceiveEventMessageCalled_NullMessageRequest() { var moduleClient = ModuleClient.CreateFromConnectionString(FakeConnectionString, TransportType.Mqtt_Tcp_Only); IDelegatingHandler innerHandler = Substitute.For <IDelegatingHandler>(); moduleClient.InnerHandler = innerHandler; bool isMessageHandlerCalled = false; await moduleClient .SetInputMessageHandlerAsync( "endpoint1", (message, context) => { isMessageHandlerCalled = true; return(Task.FromResult(MessageResponse.Completed)); }, "custom data") .ConfigureAwait(false); await moduleClient.InternalClient.OnModuleEventMessageReceivedAsync(null, null).ConfigureAwait(false); Assert.IsFalse(isMessageHandlerCalled); }
public async Task ModuleClient_SetDefaultReceiveCallbackAsync_RemoveCallback_Amqp() { var moduleClient = ModuleClient.CreateFromConnectionString(FakeConnectionString, TransportType.Amqp_Tcp_Only); IDelegatingHandler innerHandler = Substitute.For <IDelegatingHandler>(); moduleClient.InnerHandler = innerHandler; await moduleClient.SetMessageHandlerAsync((message, context) => Task.FromResult(MessageResponse.Completed), "custom data").ConfigureAwait(false); await innerHandler.Received(1).EnableEventReceiveAsync(false, Arg.Any <CancellationToken>()).ConfigureAwait(false); await innerHandler.DidNotReceiveWithAnyArgs().EnableReceiveMessageAsync(Arg.Any <CancellationToken>()).ConfigureAwait(false); await innerHandler.DidNotReceiveWithAnyArgs().DisableEventReceiveAsync(false, Arg.Any <CancellationToken>()).ConfigureAwait(false); await moduleClient.SetMessageHandlerAsync(null, null).ConfigureAwait(false); await innerHandler.Received(1).EnableEventReceiveAsync(false, Arg.Any <CancellationToken>()).ConfigureAwait(false); await innerHandler.DidNotReceiveWithAnyArgs().EnableReceiveMessageAsync(Arg.Any <CancellationToken>()).ConfigureAwait(false); await innerHandler.Received(1).DisableEventReceiveAsync(false, Arg.Any <CancellationToken>()).ConfigureAwait(false); }
async Task ExecuteWithErrorHandlingAsync(Func <Task> asyncOperation, bool ensureOpen) { if (ensureOpen) { await this.EnsureOpenAsync(); } TaskCompletionSource <int> completedPromise = this.openCompletion; IDelegatingHandler handler = this.InnerHandler; try { await asyncOperation(); } catch (Exception ex) when(!ex.IsFatal()) { if (this.IsTransient(ex)) { if (this.IsTranportTransient(ex)) { if (ex is IotHubClientTransientException) { throw; } throw new IotHubClientTransientException("Transient error occured, please retry.", ex); } this.Reset(completedPromise, handler); if (ex is IotHubClientTransientException) { throw; } throw new IotHubClientTransientException("Transient error occured, please retry.", ex); } this.Reset(completedPromise, handler); throw; } }
public IDelegatingHandler Build(PipelineContext context) { if (_pipeline.Count == 0) { throw new InvalidOperationException("Pipeline is not setup"); } IDelegatingHandler nextHandler = null; IDelegatingHandler currentHandler = null; // Initializes all handlers except the last one: the transport. // That is dynamically initialized by the ProtocolRoutingDelegatingHandler. for (int i = _pipeline.Count - 2; i >= 0; i--) { ContinuationFactory <IDelegatingHandler> currentFactory = _pipeline[i]; ContinuationFactory <IDelegatingHandler> nextFactory = _pipeline[i + 1]; currentHandler = currentFactory(context, nextHandler); currentHandler.ContinuationFactory = nextFactory; nextHandler = currentHandler; } return(currentHandler); }
// Tests_SRS_DEVICECLIENT_33_002: [** The OnReceiveEventMessageCalled shall invoke the specified delegate. **]** public async Task ModuleClient_OnReceiveEventMessageCalled_SpecifiedCallbackCalled() { var moduleClient = ModuleClient.CreateFromConnectionString(FakeConnectionString, TransportType.Mqtt_Tcp_Only); IDelegatingHandler innerHandler = Substitute.For <IDelegatingHandler>(); moduleClient.InnerHandler = innerHandler; bool isDefaultCallbackCalled = false; await moduleClient.SetMessageHandlerAsync( (message, context) => { isDefaultCallbackCalled = true; return(Task.FromResult(MessageResponse.Completed)); }, "custom data"); bool isSpecificCallbackCalled = false; await moduleClient.SetInputMessageHandlerAsync( "endpoint2", (message, context) => { isSpecificCallbackCalled = true; return(Task.FromResult(MessageResponse.Completed)); }, "custom data"); var testMessage = new Message { LockToken = "AnyLockToken", }; await moduleClient.InternalClient.OnModuleEventMessageReceivedAsync("endpoint2", testMessage).ConfigureAwait(false); Assert.IsFalse(isDefaultCallbackCalled); Assert.IsTrue(isSpecificCallbackCalled); }
public async Task RetryDelegatingHandler_SendEventAsyncRetries() { // arrange int callCounter = 0; PipelineContext contextMock = Substitute.For <PipelineContext>(); contextMock.ConnectionStatusChangesHandler = new ConnectionStatusChangesHandler(delegate(ConnectionStatus status, ConnectionStatusChangeReason reason) { }); IDelegatingHandler innerHandlerMock = Substitute.For <IDelegatingHandler>(); using var message = new Message(new MemoryStream(new byte[] { 1, 2, 3 })); innerHandlerMock .SendEventAsync(Arg.Is(message), Arg.Any <CancellationToken>()) .Returns(t => { callCounter++; Message m = t.Arg <Message>(); Stream stream = m.GetBodyStream(); if (callCounter == 1) { throw new IotHubException(TestExceptionMessage, isTransient: true); } byte[] buffer = new byte[3]; stream.Read(buffer, 0, 3); return(TaskHelpers.CompletedTask); }); var retryDelegatingHandler = new RetryDelegatingHandler(contextMock, innerHandlerMock); // act await retryDelegatingHandler.SendEventAsync(message, CancellationToken.None).ConfigureAwait(false); // assert callCounter.Should().Be(2); }
public async Task ModuleClient_SetReceiveCallbackAsync_RemoveCallback_Amqp() { ModuleClient moduleClient = await CreateAmqpModuleClientAsync(); IDelegatingHandler innerHandler = Substitute.For <IDelegatingHandler>(); moduleClient.InnerHandler = innerHandler; await moduleClient.SetInputMessageHandlerAsync("endpoint1", (message, context) => Task.FromResult(MessageResponse.Completed), "custom data").ConfigureAwait(false); await moduleClient.SetInputMessageHandlerAsync("endpoint2", (message, context) => Task.FromResult(MessageResponse.Completed), "custom data").ConfigureAwait(false); await innerHandler.Received(1).EnableEventReceiveAsync(true, Arg.Any <CancellationToken>()).ConfigureAwait(false); await innerHandler.DidNotReceiveWithAnyArgs().EnableReceiveMessageAsync(Arg.Any <CancellationToken>()).ConfigureAwait(false); await innerHandler.DidNotReceiveWithAnyArgs().DisableEventReceiveAsync(true, Arg.Any <CancellationToken>()).ConfigureAwait(false); await innerHandler.DidNotReceiveWithAnyArgs().DisableReceiveMessageAsync(Arg.Any <CancellationToken>()).ConfigureAwait(false); await moduleClient.SetInputMessageHandlerAsync("endpoint1", null, null).ConfigureAwait(false); await innerHandler.Received(1).EnableEventReceiveAsync(true, Arg.Any <CancellationToken>()).ConfigureAwait(false); await innerHandler.DidNotReceiveWithAnyArgs().EnableReceiveMessageAsync(Arg.Any <CancellationToken>()).ConfigureAwait(false); await innerHandler.DidNotReceiveWithAnyArgs().DisableEventReceiveAsync(true, Arg.Any <CancellationToken>()).ConfigureAwait(false); await moduleClient.SetInputMessageHandlerAsync("endpoint2", null, null).ConfigureAwait(false); await innerHandler.Received(1).EnableEventReceiveAsync(true, Arg.Any <CancellationToken>()).ConfigureAwait(false); await innerHandler.DidNotReceiveWithAnyArgs().EnableReceiveMessageAsync(Arg.Any <CancellationToken>()).ConfigureAwait(false); await innerHandler.Received(1).DisableEventReceiveAsync(true, Arg.Any <CancellationToken>()).ConfigureAwait(false); }
public async Task RetryDelegatingHandler_OpenAsyncRetries() { // arrange int callCounter = 0; IPipelineContext contextMock = Substitute.For <IPipelineContext>(); IDelegatingHandler innerHandlerMock = Substitute.For <IDelegatingHandler>(); innerHandlerMock.OpenAsync(Arg.Any <CancellationToken>()).Returns(t => { return(++callCounter == 1 ? throw new IotHubException("Test transient exception", isTransient: true) : TaskHelpers.CompletedTask); }); innerHandlerMock.WaitForTransportClosedAsync().Returns(Task.Delay(TimeSpan.FromSeconds(10))); var retryDelegatingHandler = new RetryDelegatingHandler(contextMock, innerHandlerMock); // act await retryDelegatingHandler.OpenAsync(new CancellationToken()).ConfigureAwait(false); // assert Assert.AreEqual(2, callCounter); }
protected DefaultDelegatingHandler(IDelegatingHandler innerHandler) { this.InnerHandler = innerHandler; }
async Task Reset(TaskCompletionSource <int> openCompletionBeforeOperationStarted, IDelegatingHandler handlerBeforeOperationStarted) { if (openCompletionBeforeOperationStarted == Volatile.Read(ref this.openCompletion)) { if (Interlocked.CompareExchange(ref this.openCompletion, null, openCompletionBeforeOperationStarted) == openCompletionBeforeOperationStarted) { await Cleanup(handlerBeforeOperationStarted).ConfigureAwait(false); } } }
DeviceClient(IotHubConnectionString iotHubConnectionString, ITransportSettings[] transportSettings) { this.iotHubConnectionString = iotHubConnectionString; #if !WINDOWS_UWP var innerHandler = new RetryDelegatingHandler( new ErrorDelegatingHandler( () => new RoutingDelegatingHandler(this.CreateTransportHandler, iotHubConnectionString, transportSettings))); #else // UWP does not support retry yet. We need to make the underlying Message stream accessible internally on UWP // to be sure that either the stream has not been read or it is seekable to safely retry operation var innerHandler = new ErrorDelegatingHandler( () => new RoutingDelegatingHandler(this.CreateTransportHandler, iotHubConnectionString, transportSettings)); #endif this.InnerHandler = new GateKeeperDelegatingHandler(innerHandler); }
DeviceClient(IotHubConnectionString iotHubConnectionString) { this.InnerHandler = new GateKeeperDelegatingHandler( new ErrorDelegatingHandler(() => new HttpTransportHandler(iotHubConnectionString))); }
public ProtocolRoutingDelegatingHandler(IPipelineContext context, IDelegatingHandler innerHandler) : base(context, innerHandler) { }
public static DelegatingHandler ToImplementation([CanBeNull] this IDelegatingHandler abstraction) { return(((IAbstraction <DelegatingHandler>)abstraction)?.UnsafeConvert()); }
async Task <T> ExecuteWithErrorHandlingAsync <T>(Func <Task <T> > asyncOperation, bool ensureOpen, CancellationToken cancellationToken) { try { if (Logging.IsEnabled) { Logging.Enter(this, ensureOpen, cancellationToken, $"{nameof(ErrorDelegatingHandler)}.{nameof(ExecuteWithErrorHandlingAsync)}"); } if (ensureOpen) { await this.EnsureOpenAsync(cancellationToken).ConfigureAwait(false); } TaskCompletionSource <int> openCompletionBeforeOperationStarted = Volatile.Read(ref this.openCompletion); IDelegatingHandler handlerBeforeOperationStarted = this.InnerHandler; try { return(await asyncOperation().ConfigureAwait(false)); } catch (Exception ex) when(!ex.IsFatal()) { if (IsTransient(ex)) { if (IsTransportHandlerStillUsable(ex)) { if (Logging.IsEnabled) { Logging.Error(this, $"Transient exception caught; IsTransportHandlerStillUsable=true : {ex}"); } if (ex is IotHubClientTransientException) { throw; } throw new IotHubClientTransientException("Transient error occurred, please retry.", ex); } await this.Reset(openCompletionBeforeOperationStarted, handlerBeforeOperationStarted).ConfigureAwait(false); if (Logging.IsEnabled) { Logging.Error(this, $"Transient exception caught; IsTransportHandlerStillUsable=false : {ex}"); } if (ex is IotHubClientTransientException) { throw; } throw new IotHubClientTransientException("Transient error occurred, please retry.", ex); } else { if (Logging.IsEnabled) { Logging.Error(this, $"Non-transient exception caught: {ex}"); } await this.Reset(openCompletionBeforeOperationStarted, handlerBeforeOperationStarted).ConfigureAwait(false); throw; } } } finally { if (Logging.IsEnabled) { Logging.Exit(this, ensureOpen, cancellationToken, $"{nameof(ErrorDelegatingHandler)}.{nameof(ExecuteWithErrorHandlingAsync)}"); } } }
async Task Reset(TaskCompletionSource <int> openCompletionBeforeOperationStarted, IDelegatingHandler handlerBeforeOperationStarted) { try { if (Logging.IsEnabled) { Logging.Enter(this, openCompletionBeforeOperationStarted, handlerBeforeOperationStarted, $"{nameof(ErrorDelegatingHandler)}.{nameof(Reset)}"); } if (openCompletionBeforeOperationStarted == Volatile.Read(ref this.openCompletion)) { if (Interlocked.CompareExchange(ref this.openCompletion, null, openCompletionBeforeOperationStarted) == openCompletionBeforeOperationStarted) { await Cleanup(handlerBeforeOperationStarted).ConfigureAwait(false); } } } finally { if (Logging.IsEnabled) { Logging.Exit(this, $"{nameof(ErrorDelegatingHandler)}.{nameof(Reset)}"); } } }
public override async Task OpenAsync(bool explicitOpen, CancellationToken cancellationToken) { try { if (Logging.IsEnabled) { Logging.Enter(this, explicitOpen, cancellationToken, $"{nameof(ErrorDelegatingHandler)}.{nameof(OpenAsync)}"); } TaskCompletionSource <int> openCompletionBeforeOperationStarted = Volatile.Read(ref this.openCompletion); if (openCompletionBeforeOperationStarted == null) { openCompletionBeforeOperationStarted = new TaskCompletionSource <int>(); TaskCompletionSource <int> currentOpenPromise; if ((currentOpenPromise = Interlocked.CompareExchange(ref this.openCompletion, openCompletionBeforeOperationStarted, null)) == null) { IDelegatingHandler handlerBeforeOperationStarted = this.ContinuationFactory(Context); this.InnerHandler = handlerBeforeOperationStarted; try { await this.ExecuteWithErrorHandlingAsync(() => base.OpenAsync(explicitOpen, cancellationToken), false, cancellationToken).ConfigureAwait(false); openCompletionBeforeOperationStarted.TrySetResult(0); } catch (Exception ex) when(IsTransportHandlerStillUsable(ex)) { await this.Reset(openCompletionBeforeOperationStarted, handlerBeforeOperationStarted).ConfigureAwait(false); throw; } catch (Exception ex) when(!ex.IsFatal()) { if (Logging.IsEnabled) { Logging.Error(this, ex.Message, $"{nameof(ErrorDelegatingHandler)}.{nameof(OpenAsync)}"); } throw; } } else { if (Logging.IsEnabled) { Logging.Info(this, "Awaiting new Open task.", $"{nameof(ErrorDelegatingHandler)}.{nameof(OpenAsync)}"); } await currentOpenPromise.Task.ConfigureAwait(false); } } else { if (Logging.IsEnabled) { Logging.Info(this, "Awaiting existing Open task.", $"{nameof(ErrorDelegatingHandler)}.{nameof(OpenAsync)}"); } await openCompletionBeforeOperationStarted.Task.ConfigureAwait(false); } } finally { if (Logging.IsEnabled) { Logging.Exit(this, explicitOpen, cancellationToken, $"{nameof(ErrorDelegatingHandler)}.{nameof(OpenAsync)}"); } } }
public GateKeeperDelegatingHandler(IDelegatingHandler innerHandler) { this.InnerHandler = innerHandler; this.thisLock = new object(); this.openTaskCompletionSource = new TaskCompletionSource <object>(this); }
public RetryDelegatingHandler(IDelegatingHandler innerHandler) : base(innerHandler) { this.retryPolicy = new RetryPolicy(new IotHubTransientErrorIgnoreStrategy(), RetryCount, TimeSpan.FromMilliseconds(100), TimeSpan.FromSeconds(10), TimeSpan.FromMilliseconds(100)); }
public ErrorDelegatingHandler(IPipelineContext context, IDelegatingHandler innerHandler) : base(context, innerHandler) { }
public GateKeeperDelegatingHandler(IDelegatingHandler innerHandler) { this.InnerHandler = innerHandler; this.thisLock = new object(); this.openTaskCompletionSource = new TaskCompletionSource<object>(this); }
public RetryDelegatingHandler(IDelegatingHandler innerHandler) :base(innerHandler) { this.retryPolicy = new RetryPolicy(new IotHubTransientErrorIgnoreStrategy(), RetryCount, TimeSpan.FromMilliseconds(100), TimeSpan.FromSeconds(10), TimeSpan.FromMilliseconds(100)); }