private void CalculateProgressBeforeRead() { var start = Progress?.NextIterationStart ?? _context.StartInstant; var endCutoffInstant = InstantUtils.SecondsAgo(_context.ClockSkewProtectionSeconds); var minEndInstant = start.Plus(Duration.FromSeconds(_context.MinIntervalSeconds)); var maxEndInstant = start.Plus(Duration.FromSeconds(_context.MaxIntervalSeconds)); var end = Progress?.NextIterationEnd ?? maxEndInstant; if (end > maxEndInstant) { end = maxEndInstant; } if (end > endCutoffInstant) { end = endCutoffInstant; } if (end < minEndInstant) { end = minEndInstant; } // Fix the iteration based on _context.End only if the _context.End is between progress start and end // (so that the iteration needs to be run partially). We don't need to consider any other cases, if // the Progress.end is passed _context.end, we won't run the iteration anyway. if (_context.EndInstant.HasValue && start < _context.EndInstant.Value && end > _context.EndInstant.Value) { end = _context.EndInstant.Value; } Progress = new JobProgress(start, end, Progress?.NextToken); }
private JobProgress CalculateProgressAfterRead() { // There's no need to consider _context.End here. We just calculate the prospective next iteration span // and it will be looked at and fixed before the next iteration, if needed. if (!string.IsNullOrWhiteSpace(_readResponse.NextToken)) { return(new JobProgress(Progress.NextIterationStart, Progress.NextIterationEnd, _readResponse.NextToken)); } // If the current timespan is completed, we start from one millisecond after the end of this timespan // because AWS APIs accept milliseconds as timespan, so the resolution is 1 ms. And the API is // inclusive for both start and end, so we don't want events with timestamp equal to previous end // be returned twice. var start = Progress.NextIterationEnd.Plus(Duration.FromMilliseconds(1)); var endCutoffInstant = InstantUtils.SecondsAgo(_context.ClockSkewProtectionSeconds); var minEndInstant = start.Plus(Duration.FromSeconds(_context.MinIntervalSeconds)); var maxEndInstant = start.Plus(Duration.FromSeconds(_context.MaxIntervalSeconds)); if (minEndInstant > endCutoffInstant) { return(new JobProgress(start, minEndInstant, null)); } var end = maxEndInstant; if (end > endCutoffInstant) { end = endCutoffInstant; } return(new JobProgress(start, end, null)); }
private static Instant?ParseAbsoluteOrRelativeTime(string absoluteTime, int?relativeTimeSecondsAgo) { if (!string.IsNullOrWhiteSpace(absoluteTime)) { var parsedTime = InstantPattern.Parse(absoluteTime); if (!parsedTime.Success) { throw new ArgumentException($"Time pattern '{absoluteTime}' could not be parsed. ISO-8601 based UTC format without fractions of second is expected."); } return(parsedTime.Value); } if (relativeTimeSecondsAgo.HasValue) { return(InstantUtils.SecondsAgo(relativeTimeSecondsAgo.Value)); } return(null); }
private bool IsRunnable(JobProgress progress) { if (_context.EndInstant.HasValue) { // Just check for the end. If this would have been a partial iteration (_context.End was between // Progress.Start and Progress.End), CalculateProgressBeforeRead method would have been adjusted it. if (progress.NextIterationEnd > _context.EndInstant.Value) { return(false); } // If the Progress.End is exactly equal to _context.End, allow it to be run without any regard // to cut-off, since it's the last iteration ever to be run. if (progress.NextIterationEnd == _context.EndInstant.Value) { return(true); } } var endCutoffInstant = InstantUtils.SecondsAgo(_context.ClockSkewProtectionSeconds); return(progress.NextIterationEnd <= endCutoffInstant); }