private static void PublishEvent(ILogger logger, ISupportNotifier supportNotifier, IAsyncCollector <Message> messageAsyncCollector, Event eventModel) { var eventId = StaticSettings.EventId(MethodEventBase, (int)EventType.ChangeFeed); try { messageAsyncCollector.AddAsync(eventModel.ToMessage()); logger.LogInformation(eventId, StaticSettings.Template, EventTrigger, eventModel.CorrelationId, EntityType, eventModel.EventId, PublishMessage.PublishedApplicationEvent.ToString()); } catch (Exception ex) { logger.LogError(eventId, ex, StaticSettings.Template, EventTrigger, eventModel.CorrelationId, EntityType, eventModel.EventId, ex.Message); // notify support of unknown exception supportNotifier.Notify($"WJ Unhandled Exception. Operation: {OperationName}, body: {JsonConvert.SerializeObject(eventModel)}, Message: {ex.Message}"); } }
public static async Task <IActionResult> Run( [HttpTrigger(AuthorizationLevel.Anonymous, Method, Route = Route)] HttpRequestMessage request, [CosmosDBTrigger(StaticSettings.Db, StaticSettings.Collection, ConnectionStringSetting = StaticSettings.DbConnectionStringSetting)] IDocumentClient documentClient, ISupportNotifier supportNotifier, ILogger logger) { // get the correlation identifier request.Headers.TryGetValues(CorrelationIdHeaderKey, out var headerValues); var correlationId = headerValues == null?Guid.NewGuid().ToString() : headerValues.First(); // ProcessStep.Deserialize - deserialize request content EventRequest eventRequest; string payload = null; var eventId = StaticSettings.EventId(MethodLevelEventId, (int)ProcessStep.Deserialize, ProcessStep.Deserialize.ToString()); try { payload = await request.Content.ReadAsStringAsync(); eventRequest = JsonConvert.DeserializeObject <EventRequest>(payload); logger.LogInformation(eventId, StaticSettings.Template, OperationName, correlationId); } catch (ArgumentNullException ex) { return(BadRequest(logger, eventId, correlationId, ex.Message)); } catch (ArgumentException ex) { return(BadRequest(logger, eventId, correlationId, ex.Message)); } catch (Exception e) { return(BadRequest(logger, supportNotifier, eventId, correlationId, e, payload)); } // ProcessStep.Validation - validate the event request eventId = StaticSettings.EventId(MethodLevelEventId, (int)ProcessStep.Validation, ProcessStep.Validation.ToString()); try { Validator.ValidateObject(eventRequest, new ValidationContext(eventRequest)); logger.LogInformation(eventId, StaticSettings.Template, OperationName, correlationId); } catch (ValidationException) { return(BadRequest(logger, eventId, correlationId, "Invalid request content")); } catch (Exception e) { return(BadRequest(logger, supportNotifier, eventId, correlationId, e, payload)); } var docUri = UriFactory.CreateDocumentCollectionUri(StaticSettings.Db, StaticSettings.Collection); // check for valid event sequence of the event in our event store // This may result in a stale sequence number, but we catch that in the "create document" step if (eventRequest.EventPurpose != EventPurpose.CreateAggregate) { eventId = StaticSettings.EventId(MethodLevelEventId, (int)ProcessStep.SequenceValidation); var sequenceValidated = true; try { Policy.Handle <Exception>() .WaitAndRetry(RetryCount, RetryDuration, (ex, c) => logger.LogWarning(eventId, StaticSettings.Template, EventTrigger, correlationId, EntityType, eventRequest.EventId, $"{ProcessStep.SequenceValidation.ToString()} retryTime: {c}, {ex.Message}")) .Execute(ct => { sequenceValidated = TryExecuteSequenceValidation(logger, eventId, correlationId, documentClient, docUri, eventRequest); }, CancellationToken.None); } catch (Exception ex) { return(BadRequest(logger, supportNotifier, eventId, correlationId, ProcessStep.SequenceValidation, ex, payload)); } if (!sequenceValidated) { return(BadRequest(logger, eventId, correlationId, ProcessStep.SequenceValidation, payload)); } } // Create document // todo: implement retry eventId = StaticSettings.EventId(MethodLevelEventId, (int)ProcessStep.CreateDocument); try { await documentClient.CreateDocumentAsync(docUri, eventRequest); logger.LogInformation(eventId, StaticSettings.Template, EventTrigger, correlationId, EntityType, eventRequest.EventId, ProcessStep.CreateDocument.ToString()); return(new OkResult()); } // If either documentsFeedOrDatabaseLink or document is not set. catch (ArgumentNullException) { return(BadRequest(logger, eventId, correlationId, ProcessStep.CreateDocument, CreateDocumentMessage.DocumentNull.ToString())); } // Represents a consolidation of failures that occured during async processing. // Look within InnerExceptions to find the actual exception(s) catch (AggregateException) { // todo: log inner exceptions individually return(BadRequest(logger, eventId, correlationId, ProcessStep.CreateDocument, CreateDocumentMessage.Aggregate.ToString())); } catch (DocumentClientException ex) { return(BadRequest(logger, supportNotifier, eventId, correlationId, ex, payload)); } catch (Exception ex) { return(BadRequest(logger, supportNotifier, eventId, correlationId, ProcessStep.CreateDocument, ex, payload)); } }