예제 #1
0
        /// <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]));
        }
예제 #2
0
        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));
        }
예제 #3
0
        /// <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]));
        }
예제 #4
0
        /// <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));
        }