public async Task RouteNotification(IRequestDescriptor <TDescriptor> descriptors, Notification notification, CancellationToken token) { using (_activityTracingStrategy?.ApplyInbound(notification) ?? Disposable.Empty) { using var debug = _logger.TimeDebug("Routing Notification {Method}", notification.Method); using var _ = _logger.BeginScope( new[] { new KeyValuePair <string, string?>("Method", notification.Method), new KeyValuePair <string, string?>("Params", notification.Params?.ToString()) } ); object? @params = null; if (!(descriptors.Default?.Params is null)) { if (descriptors.Default.IsDelegatingHandler) { _logger.LogTrace( "Converting params for Notification {Method} to {Type}", notification.Method, descriptors.Default.Params.GetGenericArguments()[0].FullName ); var o = notification.Params?.ToObject(descriptors.Default.Params.GetGenericArguments()[0], _serializer.JsonSerializer); @params = Activator.CreateInstance(descriptors.Default.Params, o); } else { _logger.LogTrace("Converting params for Notification {Method} to {Type}", notification.Method, descriptors.Default.Params.FullName); @params = notification.Params?.ToObject(descriptors.Default.Params, _serializer.JsonSerializer); } } await Task.WhenAll(descriptors.Select(descriptor => InnerRoute(_serviceScopeFactory, descriptor, @params, token))).ConfigureAwait(false); }
private ProcessSchedulerDelegate BuildNotificationDelegate(IRequestDescriptor <IHandlerDescriptor?> descriptors, Notification notification) { return(async(cancellationToken) => { using var timeoutCts = new CancellationTokenSource(_requestTimeout); using var combinedCts = CancellationTokenSource.CreateLinkedTokenSource(timeoutCts.Token, cancellationToken); using var timer = _logger.TimeDebug("Processing notification {Method}", notification.Method); try { await _requestRouter.RouteNotification(descriptors, notification, combinedCts.Token).ConfigureAwait(false); } catch (OperationCanceledException) { if (timeoutCts.IsCancellationRequested) { _logger.LogTrace("Notification {Method} was cancelled due to timeout", notification.Method); return; } _logger.LogTrace("Notification {Method} was cancelled", notification.Method); } catch (Exception e) { _logger.LogCritical(Events.UnhandledRequest, e, "Failed to handle notification {Method}", notification.Method); } }); }
public async Task <ErrorResponse> RouteRequest(IRequestDescriptor <IHandlerDescriptor> descriptors, Request request, CancellationToken cancellationToken) { _onRequestCallback?.Invoke(); await Task.Delay(_routeDelay, cancellationToken).ConfigureAwait(false); var successfulResponse = new TestSuccessfulResponse(request.Id, request); return(new ErrorResponse(successfulResponse)); }
private ProcessSchedulerDelegate BuildRequestDelegate(IRequestDescriptor <IHandlerDescriptor?> descriptors, Request request, RequestInvocationHandle handle) { return(async(cancellationToken) => { try { var result = await InvokeRequestAsync(cancellationToken).ConfigureAwait(false); _outputHandler.Send(result.Value); } finally { handle.Dispose(); } }); async Task <ErrorResponse> InvokeRequestAsync(CancellationToken cancellationToken) { using var timeoutCts = new CancellationTokenSource(_requestTimeout); using var combinedCts = CancellationTokenSource.CreateLinkedTokenSource(handle.CancellationTokenSource.Token, timeoutCts.Token, cancellationToken); using var timer = _logger.TimeDebug("Processing request {Method}:{Id}", request.Method, request.Id); try { var result = await _requestRouter.RouteRequest(descriptors, request, combinedCts.Token).ConfigureAwait(false); return(result); } catch (OperationCanceledException) { if (timeoutCts.IsCancellationRequested) { _logger.LogTrace("Request {Method}:{Id} was cancelled, due to timeout", request.Method, request.Id); return(new RequestCancelled(request.Id, request.Method)); } _logger.LogTrace("Request {Method}:{Id} was cancelled", request.Method, request.Id); return(new RequestCancelled(request.Id, request.Method)); } catch (RpcErrorException e) { _logger.LogCritical(Events.UnhandledRequest, e, "Failed to handle request {Method}:{Id}", request.Method, request.Id); return(new RpcError( request.Id, request.Method, new ErrorMessage(e.Code, e.Message, e.Error))); } catch (Exception e) { _logger.LogCritical(Events.UnhandledRequest, e, "Failed to handle request {Method}:{Id}. Unhandled exception", request.Method, request.Id); return(new InternalError(request.Id, request.Method, e.ToString())); } } }
public override void InvokeNotification(IRequestDescriptor <IHandlerDescriptor?> descriptor, Notification notification) { if (descriptor.Default is null) { throw new ArgumentNullException(nameof(descriptor.Default)); } var type = _requestProcessIdentifier.Identify(descriptor.Default); var schedulerDelegate = RouteNotification(descriptor, notification); _processScheduler.Add(type, notification.Method, schedulerDelegate); }
private SchedulerDelegate RouteNotification( IRequestDescriptor <IHandlerDescriptor?> descriptors, Notification notification) => (_, scheduler) => // ITS A RACE! Observable.Amb( Observable.Timer(_options.RequestTimeout, scheduler) .Select(_ => Unit.Default) .Do( _ => _logger.LogTrace("Notification was cancelled due to timeout") ), Observable.FromAsync(
public async Task RouteNotification(IRequestDescriptor <IHandlerDescriptor> descriptors, Notification notification, CancellationToken cancellationToken) { try { await Task.Delay(_routeDelay, cancellationToken).ConfigureAwait(false); } catch (OperationCanceledException) { OnNotificationCancelled?.Invoke(notification); throw; } OnNotificationCompleted?.Invoke(notification); }
public override RequestInvocationHandle InvokeRequest(IRequestDescriptor <IHandlerDescriptor?> descriptor, Request request) { if (descriptor.Default is null) { throw new ArgumentNullException(nameof(descriptor.Default)); } var handle = new RequestInvocationHandle(request); var type = _requestProcessIdentifier.Identify(descriptor.Default); var schedulerDelegate = RouteRequest(descriptor, request, handle); _processScheduler.Add(type, $"{request.Method}:{request.Id}", schedulerDelegate); return(handle); }
Task IRequestRouter <IHandlerDescriptor?> .RouteNotification(IRequestDescriptor <IHandlerDescriptor?> descriptors, Notification notification, CancellationToken token) => RouteNotification(
private SchedulerDelegate RouteRequest( IRequestDescriptor <IHandlerDescriptor?> descriptor, Request request, RequestInvocationHandle handle) { var cts = handle.CancellationTokenSource; return((contentModifiedToken, scheduler) => Observable.Create <ErrorResponse>( observer => { // ITS A RACE! var sub = Observable.Amb( contentModifiedToken.Select( _ => { _logger.LogTrace( "Request {Id} was abandoned due to content be modified", request.Id ); return new ErrorResponse( new ContentModified(request.Id, request.Method) ); } ), Observable.Timer(_options.RequestTimeout, scheduler).Select( _ => new ErrorResponse(new RequestCancelled(request.Id, request.Method)) ), Observable.FromAsync( async ct => { using var timer = _logger.TimeDebug( "Processing request {Method} {ResponseId}", request.Method, request.Id ); ct.Register(cts.Cancel); // ObservableToToken(contentModifiedToken).Register(cts.Cancel); try { var result = await _requestRouter.RouteRequest( descriptor, request, cts.Token ).ConfigureAwait(false); return result; } catch (OperationCanceledException) { _logger.LogTrace("Request {Id} was cancelled", request.Id); return new RequestCancelled(request.Id, request.Method); } catch (RpcErrorException e) { _logger.LogCritical( Events.UnhandledRequest, e, "Failed to handle request {Method} {RequestId}", request.Method, request.Id ); return new RpcError( request.Id, request.Method, new ErrorMessage(e.Code, e.Message, e.Error) ); } catch (Exception e) { _logger.LogCritical( Events.UnhandledRequest, e, "Failed to handle request {Method} {RequestId}", request.Method, request.Id ); return new InternalError(request.Id, request.Method, e.ToString()); } } ) ) .Subscribe(observer); return new CompositeDisposable(sub, handle); } ) .Select( response => { _outputHandler.Send(response.Value); return Unit.Default; } )); }
public abstract RequestInvocationHandle InvokeRequest(IRequestDescriptor <IHandlerDescriptor?> descriptor, Request request);
public abstract void InvokeNotification(IRequestDescriptor <IHandlerDescriptor?> descriptor, Notification notification);