public async Task <DateTime?> FetchSince(DateTime cursor) { using (_logger.Scope("Fetching all new incidents since {Cursor}.", cursor)) { var incidents = (await _incidentApiClient.GetIncidents(GetRecentIncidentsQuery(cursor))) // The incident API trims the milliseconds from any filter. // Therefore, a query asking for incidents newer than '2018-06-29T00:00:00.5Z' will return an incident from '2018-06-29T00:00:00.25Z' // We must perform a check on the CreateDate ourselves to verify that no old incidents are returned. .Where(i => i.CreateDate > cursor) .ToList(); _logger.LogInformation("Found {IncidentCount} incidents to parse.", incidents.Count); var parsedIncidents = incidents .SelectMany(_aggregateIncidentParser.ParseIncident) .ToList(); _logger.LogInformation("Parsed {ParsedIncidentCount} incidents.", parsedIncidents.Count); foreach (var parsedIncident in parsedIncidents.OrderBy(i => i.StartTime)) { using (_logger.Scope("Creating incident for parsed incident with ID {ParsedIncidentID} affecting {ParsedIncidentPath} at {ParsedIncidentStartTime} with status {ParsedIncidentStatus}.", parsedIncident.Id, parsedIncident.AffectedComponentPath, parsedIncident.StartTime, parsedIncident.AffectedComponentStatus)) { await _incidentFactory.CreateAsync(parsedIncident); } } return(incidents.Any() ? incidents.Max(i => i.CreateDate) : (DateTime?)null); } }
public async Task <TAggregationEntity> GetAsync(ParsedIncident input) { TAggregationEntity aggregationEntity = null; var possiblePath = _aggregationPathProvider.Get(input); // Find an aggregation to link to var possibleAggregationsQuery = _table .CreateQuery <TAggregationEntity>() .Where(e => // The aggregation must affect the same path e.AffectedComponentPath == possiblePath && // The aggregation must begin before or at the same time e.StartTime <= input.StartTime); // The aggregation must cover the same time period if (input.IsActive) { // An active input can only be linked to an active aggregation possibleAggregationsQuery = possibleAggregationsQuery .Where(e => e.IsActive); } else { // An inactive input can be linked to an active aggregation or an inactive aggregation that ends after it possibleAggregationsQuery = possibleAggregationsQuery .Where(e => e.IsActive || e.EndTime >= input.EndTime); } var possibleAggregations = possibleAggregationsQuery .ToList(); _logger.LogInformation("Found {AggregationCount} possible aggregations to link entity to with path {AffectedComponentPath}.", possibleAggregations.Count(), possiblePath); foreach (var possibleAggregation in possibleAggregations) { if (await _strategy.CanBeAggregatedByAsync(input, possibleAggregation)) { _logger.LogInformation("Linking entity to aggregation."); aggregationEntity = possibleAggregation; break; } } if (aggregationEntity == null) { _logger.LogInformation("Could not find existing aggregation to link to, creating new aggregation to link entity to."); aggregationEntity = await _aggregationFactory.CreateAsync(input); _logger.LogInformation("Created new aggregation {AggregationRowKey} to link entity to.", aggregationEntity.RowKey); } return(aggregationEntity); }