/// <inheritdoc /> public Task <Result <CheckpointState> > GetCheckpointStateAsync(OperationContext context) { return(context.PerformOperationAsync( Tracer, async() => { var(checkpoints, startCursor) = await ExecuteRedisFallbackAsync(context, async redisDb => Result.Success(await redisDb.ExecuteBatchAsync(context, batch => batch.GetCheckpointsInfoAsync(_checkpointsKey, _clock.UtcNow), RedisOperation.GetCheckpoint))) .ThrowIfFailureAsync(); var roleResult = await UpdateRoleAsync(context, release: false); if (!roleResult.Succeeded) { return new ErrorResult(roleResult).AsResult <Result <CheckpointState> >(); } _role = roleResult.Value; var maxCheckpoint = checkpoints.MaxByOrDefault(c => c.CheckpointCreationTime); if (maxCheckpoint == null) { Tracer.Debug(context, $"Getting checkpoint state: Can't find a checkpoint: Start cursor time: {startCursor}"); // Add slack for start cursor to account for clock skew between event hub and redis var epochStartCursor = startCursor - _configuration.EventStore.NewEpochEventStartCursorDelay; return CheckpointState.CreateUnavailable(_role.Value, epochStartCursor); } Tracer.Debug(context, $"Getting checkpoint state: Found checkpoint '{maxCheckpoint}'"); return Result.Success(new CheckpointState(_role.Value, new EventSequencePoint(maxCheckpoint.SequenceNumber), maxCheckpoint.CheckpointId, maxCheckpoint.CheckpointCreationTime)); }, Counters[GlobalStoreCounters.GetCheckpointState])); }
public Task <Result <CheckpointState> > GetCheckpointStateAsync(OperationContext context) { // NOTE: this function is naturally retried by the heartbeat mechanisms in LLS return(context.PerformOperationWithTimeoutAsync( Tracer, async context => { var blobs = ListBlobsRecentFirstAsync(context); await foreach (var blob in blobs) { try { var checkpointState = await _storage.ReadAsync <CheckpointState>(context, blob).ThrowIfFailureAsync(); checkpointState.FileName = blob; foreach (var consumer in checkpointState.Consumers) { _pushLocations.Add(consumer, _configuration.PushCheckpointCandidateExpiry); } return Result.Success(checkpointState); } catch (TaskCanceledException) when(context.Token.IsCancellationRequested) { // We hit timeout or a proper cancellation. // Breaking from the loop instead of tracing error for each iteration. break; } catch (Exception e) { Tracer.Error(context, e, $"Failed to obtain {nameof(CheckpointState)} from blob `{blob.Name}`. Skipping."); continue; } } // Add slack for start cursor to account for clock skew return CheckpointState.CreateUnavailable(_clock.UtcNow - _configuration.NewEpochEventStartCursorDelay); }, extraEndMessage: result => { if (!result.Succeeded) { return string.Empty; } var checkpointState = result.Value; return $"CheckpointId=[{checkpointState.CheckpointId}] SequencePoint=[{checkpointState.StartSequencePoint}]"; }, timeout: _configuration.CheckpointStateTimeout)); }
/// <inheritdoc /> public Task <Result <CheckpointState> > GetCheckpointStateAsync(OperationContext context) { return(context.PerformOperationAsync( Tracer, async() => { var(checkpoints, startCursor) = await _checkpointsKey.UseNonConcurrentReplicatedHashAsync( context, Configuration.RetryWindow, RedisOperation.GetCheckpoint, (batch, key) => batch.GetCheckpointsInfoAsync(key, _clock.UtcNow), timeout: Configuration.ClusterRedisOperationTimeout) .ThrowIfFailureAsync(); var roleResult = await UpdateRoleAsync(context, release: false); if (!roleResult.Succeeded) { return new ErrorResult(roleResult).AsResult <Result <CheckpointState> >(); } _role = roleResult.Value; var masterName = await _masterLeaseKey.UseNonConcurrentReplicatedHashAsync( context, Configuration.RetryWindow, RedisOperation.GetCheckpoint, (batch, key) => batch.AddOperation("GetRole", b => b.HashGetAsync(key, "M#1.MachineName")), timeout: Configuration.ClusterRedisOperationTimeout) .ThrowIfFailureAsync(); var masterLocation = masterName.IsNull ? default(MachineLocation) : new MachineLocation((string)masterName); var maxCheckpoint = checkpoints.MaxByOrDefault(c => c.CheckpointCreationTime); if (maxCheckpoint == null) { Tracer.Debug(context, $"Getting checkpoint state: Can't find a checkpoint: Start cursor time: {startCursor}"); // Add slack for start cursor to account for clock skew between event hub and redis var epochStartCursor = startCursor - Configuration.EventStore.NewEpochEventStartCursorDelay; return CheckpointState.CreateUnavailable(_role.Value, epochStartCursor, masterLocation); } Tracer.Debug(context, $"Getting checkpoint state: Found checkpoint '{maxCheckpoint}'"); return Result.Success(new CheckpointState(_role.Value, new EventSequencePoint(maxCheckpoint.SequenceNumber), maxCheckpoint.CheckpointId, maxCheckpoint.CheckpointCreationTime, new MachineLocation(maxCheckpoint.MachineName), masterLocation)); }, Counters[GlobalStoreCounters.GetCheckpointState])); }
/// <inheritdoc /> public Task <Result <CheckpointState> > GetCheckpointStateAsync(OperationContext context) { return(context.PerformOperationAsync( Tracer, async() => { var(checkpoints, startCursor) = await _checkpointsKey.UseReplicatedHashAsync( context, _configuration.RetryWindow, RedisOperation.GetCheckpoint, (batch, key) => batch.GetCheckpointsInfoAsync(key, _clock.UtcNow)) .ThrowIfFailureAsync(); var roleResult = await UpdateRoleAsync(context, release: false); if (!roleResult.Succeeded) { return new ErrorResult(roleResult).AsResult <Result <CheckpointState> >(); } _role = roleResult.Value; var maxCheckpoint = checkpoints.MaxByOrDefault(c => c.CheckpointCreationTime); if (maxCheckpoint == null) { Tracer.Debug(context, $"Getting checkpoint state: Can't find a checkpoint: Start cursor time: {startCursor}"); // Add slack for start cursor to account for clock skew between event hub and redis var epochStartCursor = startCursor - _configuration.EventStore.NewEpochEventStartCursorDelay; return CheckpointState.CreateUnavailable(_role.Value, epochStartCursor); } Tracer.Debug(context, $"Getting checkpoint state: Found checkpoint '{maxCheckpoint}'"); return Result.Success(new CheckpointState(_role.Value, new EventSequencePoint(maxCheckpoint.SequenceNumber), maxCheckpoint.CheckpointId, maxCheckpoint.CheckpointCreationTime, new MachineLocation(maxCheckpoint.MachineName))); }, Counters[GlobalStoreCounters.GetCheckpointState], // Using a timeout to make sure the operation finishes: this is important because we want for heartbeat operations // that call this method to keep running to avoid stale checkpoints. timeout: Configuration.GetCheckpointStateTimeout)); }