private async Task <long> RestartPartition(int partition, int partitionsCount, long start, long end)
        {
            var query = new ReadStreamQuery(settings.StreamName)
            {
                Coordinates = new StreamCoordinates(new[] { new StreamPosition {
                                                                Offset = start, Partition = partition
                                                            } }),
                ClientShard      = partition,
                ClientShardCount = partitionsCount,
                Limit            = (int)Math.Min(end - start, settings.EventsReadBatchSize)
            };

            var result = await ReadAsync(query).ConfigureAwait(false);

            try
            {
                HandleEvents(result, query.Coordinates);

                foreach (var window in windows)
                {
                    window.Value.Flush(true);
                }
            }
            finally
            {
                result.Dispose();
            }

            return(result.Next.Positions.Single().Offset);
        }
Пример #2
0
            public async Task HandleAsync(ReadStreamQuery query, ReadStreamResult streamResult, CancellationToken cancellationToken)
            {
                using (iterationMetric?.For("transform_time").Measure())
                {
                    var resultingEvents = streamResult.Payload.Events as IEnumerable <HerculesEvent>;

                    if (settings.Filter != null)
                    {
                        resultingEvents = resultingEvents.Where(settings.Filter);
                    }

                    if (settings.Transformer != null)
                    {
                        resultingEvents = resultingEvents.SelectMany(Transform);
                    }

                    buffer.Clear();
                    buffer.AddRange(resultingEvents);
                }

                if (buffer.Count == 0)
                {
                    return;
                }

                using (iterationMetric?.For("write_time").Measure())
                {
                    await writer.WriteEvents(buffer, cancellationToken).ConfigureAwait(false);
                }

                log.Info("Inserted {EventsCount} event(s) into target stream '{TargetStream}'.", buffer.Count, settings.TargetStreamName);
                eventsMetric?.For("out").Add(buffer.Count);

                buffer.Clear();
            }
        /// <inheritdoc />
        public async Task <ReadStreamResult <T> > ReadAsync(ReadStreamQuery query, TimeSpan timeout, CancellationToken cancellationToken = default)
        {
            var result = await client.ReadAsync(query, settings.ApiKeyProvider(), timeout, cancellationToken).ConfigureAwait(false);

            if (!result.IsSuccessful)
            {
                return(new ReadStreamResult <T>(result.Status, null, result.ErrorDetails));
            }

            var payload = result.Payload;

            try
            {
                var events = EventsBinaryReader.Read(payload.Content, settings.EventBuilderProvider, log);
                return(new ReadStreamResult <T>(result.Status, new ReadStreamPayload <T>(events, payload.Next)));
            }
            catch (Exception error)
            {
                log.Warn(error);
                return(new ReadStreamResult <T>(HerculesStatus.UnknownError, null, error.Message));
            }
            finally
            {
                payload.Dispose();
            }
        }
        private async Task <RawReadStreamPayload> ReadAsync()
        {
            var query = new ReadStreamQuery(settings.StreamName)
            {
                Coordinates      = coordinates,
                ClientShard      = shardingSettings.ClientShardIndex,
                ClientShardCount = shardingSettings.ClientShardCount,
                Limit            = settings.EventsReadBatchSize
            };

            return(await ReadAsync(query).ConfigureAwait(false));
        }
Пример #5
0
        public async Task <RawReadStreamResult> ReadAsync(ReadStreamQuery query, string apiKey, TimeSpan timeout, CancellationToken cancellationToken = default)
        {
            try
            {
                var url = new RequestUrlBuilder("stream/read")
                {
                    { Constants.QueryParameters.Stream, query.Name },
                    { Constants.QueryParameters.Limit, query.Limit },
                    { Constants.QueryParameters.ClientShard, query.ClientShard },
                    { Constants.QueryParameters.ClientShardCount, query.ClientShardCount }
                }
                .Build();

                var body = CreateRequestBody(query.Coordinates ?? StreamCoordinates.Empty);

                var request = Request
                              .Post(url)
                              .WithContentTypeHeader(Constants.ContentTypes.OctetStream)
                              .WithContent(body);

                if (compressionEnabled)
                {
                    request = request.WithAcceptEncodingHeader(Constants.Compression.Lz4Encoding);
                }

                if (!string.IsNullOrEmpty(apiKey))
                {
                    request = request.WithHeader(Constants.HeaderNames.ApiKey, apiKey);
                }

                var result = await client
                             .SendAsync(request, timeout, cancellationToken : cancellationToken)
                             .ConfigureAwait(false);

                var operationStatus = responseAnalyzer.Analyze(result.Response, out var errorMessage);
                if (operationStatus != HerculesStatus.Success)
                {
                    if (result.Response.HasContent)
                    {
                        bufferPool.Return(result.Response.Content.Buffer);
                    }

                    return(new RawReadStreamResult(operationStatus, null, errorMessage));
                }

                return(new RawReadStreamResult(operationStatus, ParseReadResponseBody(result.Response)));
            }
            catch (Exception error)
            {
                log.Warn(error);
                return(new RawReadStreamResult(HerculesStatus.UnknownError, null, error.Message));
            }
        }
Пример #6
0
        public static void WaitForAnyRecord(this IHerculesStreamClient client, string stream)
        {
            var readQuery = new ReadStreamQuery(stream)
            {
                Limit            = 1,
                Coordinates      = new StreamCoordinates(new StreamPosition[0]),
                ClientShard      = 0,
                ClientShardCount = 1
            };

            new Action(() => client.Read(readQuery, 20.Seconds()).Payload.Events.Should().NotBeEmpty())
            .ShouldPassIn(20.Seconds());
        }
Пример #7
0
        public static List <HerculesEvent>[] ReadEvents(
            this IHerculesStreamClient client,
            string stream,
            int count,
            int limit,
            int clientShards,
            StreamCoordinates coordinates = null)
        {
            var timeout = 30.Seconds();

            var stopwatch  = Stopwatch.StartNew();
            var eventsRead = 0;

            var clientShardTasks = Enumerable.Range(0, clientShards).Select(ReadSingleClientShard);

            var events = Task.WhenAll(clientShardTasks).GetAwaiter().GetResult();

            events.Sum(x => x.Count).Should().Be(count);
            return(events);

            async Task <List <HerculesEvent> > ReadSingleClientShard(int clientShard)
            {
                var shardEvents = new List <HerculesEvent>();
                var readQuery   = new ReadStreamQuery(stream)
                {
                    Limit            = limit,
                    Coordinates      = coordinates ?? StreamCoordinates.Empty,
                    ClientShard      = clientShard,
                    ClientShardCount = clientShards
                };

                while (stopwatch.Elapsed < timeout && eventsRead < count)
                {
                    var result = await client.ReadAsync(readQuery, timeout);

                    result.IsSuccessful.Should().BeTrue();

                    var eventsFromResponse = result.Payload.Events;

                    shardEvents.AddRange(eventsFromResponse);
                    readQuery.Coordinates = result.Payload.Next;
                    Interlocked.Add(ref eventsRead, eventsFromResponse.Count);
                    await Task.Delay(100);
                }

                return(shardEvents);
            }
        }
        protected private async Task <RawReadStreamPayload> ReadAsync(ReadStreamQuery query)
        {
            using (new OperationContextToken("ReadEvents"))
                using (var traceBuilder = tracer.BeginConsumerCustomOperationSpan("Read"))
                    using (iterationMetric?.For("read_time").Measure())
                    {
                        traceBuilder.SetShard(query.ClientShard, query.ClientShardCount);
                        traceBuilder.SetStream(settings.StreamName);
                        traceBuilder.SetCoordinates(query.Coordinates);

                        log.Info(
                            "Reading {EventsCount} events from stream '{StreamName}'. " +
                            "Sharding settings: shard with index {ShardIndex} from {ShardCount}. " +
                            "Coordinates: {StreamCoordinates}.",
                            query.Limit,
                            settings.StreamName,
                            query.ClientShard,
                            query.ClientShardCount,
                            query.Coordinates);
                        traceBuilder.SetOperationDetails(query.Limit);

                        RawReadStreamResult readResult;

                        do
                        {
                            readResult = await client.ReadAsync(query, settings.ApiKeyProvider(), settings.EventsReadTimeout).ConfigureAwait(false);

                            if (!readResult.IsSuccessful)
                            {
                                log.Warn(
                                    "Failed to read events from Hercules stream '{StreamName}'. " +
                                    "Status: {Status}. Error: '{Error}'.",
                                    settings.StreamName,
                                    readResult.Status,
                                    readResult.ErrorDetails);
                                await DelayOnError().ConfigureAwait(false);
                            }
                        } while (!readResult.IsSuccessful);

                        log.Info(
                            "Read {BytesCount} byte(s) from Hercules stream '{StreamName}'.",
                            readResult.Payload.Content.Count,
                            settings.StreamName);

                        return(readResult.Payload);
                    }
        }
Пример #9
0
            public async Task <ReadStreamResult <HerculesEvent> > ReadAsync(ReadStreamQuery query, TimeSpan timeout, CancellationToken cancellationToken = default)
            {
                var result = await client.ReadAsync(query, timeout, cancellationToken).ConfigureAwait(false);

                return(result.ToGenericResult());
            }
Пример #10
0
 public static ReadStreamResult Read(
     [NotNull] this IHerculesStreamClient client,
     [NotNull] ReadStreamQuery query,
     TimeSpan timeout,
     CancellationToken cancellationToken = default) =>
 client.ReadAsync(query, timeout, cancellationToken).GetAwaiter().GetResult();
 public Task HandleAsync(ReadStreamQuery query, ReadStreamResult <T> streamResult, CancellationToken cancellationToken) =>
 handler(query, streamResult, cancellationToken);
Пример #12
0
        public async Task <(ReadStreamQuery query, ReadStreamResult <T> result)> ReadAsync(
            StreamCoordinates coordinates,
            StreamShardingSettings shardingSettings,
            long additionalLimit,
            CancellationToken cancellationToken = default)
        {
            log.Info(
                "Reading logical shard with index {ClientShard} from {ClientShardCount}.",
                shardingSettings.ClientShardIndex,
                shardingSettings.ClientShardCount);

            log.Debug("Current coordinates: {StreamCoordinates}.", coordinates);

            var eventsQuery = new ReadStreamQuery(settings.StreamName)
            {
                Coordinates      = coordinates,
                ClientShard      = shardingSettings.ClientShardIndex,
                ClientShardCount = shardingSettings.ClientShardCount,
                Limit            = (int)Math.Min(settings.EventsReadBatchSize, additionalLimit)
            };

            ReadStreamResult <T> readResult;
            var remainingAttempts = settings.EventsReadAttempts;

            do
            {
                remainingAttempts--;
                readResult = await settings.StreamClient.ReadAsync(eventsQuery, settings.EventsReadTimeout, cancellationToken).ConfigureAwait(false);

                if (!readResult.IsSuccessful && !cancellationToken.IsCancellationRequested)
                {
                    log.Warn(
                        "Failed to read events from Hercules stream '{StreamName}'. " +
                        "Status: {Status}. Error: '{Error}'. " +
                        "Will try again {RemainingAttempts} more times.",
                        settings.StreamName,
                        readResult.Status,
                        readResult.ErrorDetails,
                        remainingAttempts);
                    if (remainingAttempts > 0)
                    {
                        await Task.Delay(settings.DelayOnError, cancellationToken).SilentlyContinue().ConfigureAwait(false);
                    }
                }
            } while (!cancellationToken.IsCancellationRequested && !readResult.IsSuccessful && remainingAttempts > 0);

            if (readResult.IsSuccessful)
            {
                log.Info(
                    "Read {EventsCount} event(s) from Hercules stream '{StreamName}'.",
                    readResult.Payload.Events.Count,
                    settings.StreamName);
            }
            else if (cancellationToken.IsCancellationRequested)
            {
                log.Info("Cancelled read events request from Hercules stream '{StreamName}'.",
                         settings.StreamName);
            }
            else
            {
                log.Error(
                    "Failed to read events from Hercules stream '{StreamName}'. " +
                    "Status: {Status}. Error: '{Error}'.",
                    settings.StreamName,
                    readResult.Status,
                    readResult.ErrorDetails);
            }

            return(eventsQuery, readResult);
        }
Пример #13
0
        public async Task <ReadStreamResult> ReadAsync(ReadStreamQuery query, TimeSpan timeout, CancellationToken cancellationToken = new CancellationToken())
        {
            var result = await client.ReadAsync(query, timeout, cancellationToken).ConfigureAwait(false);

            return(result.FromGenericResult());
        }
 public Task HandleAsync(ReadStreamQuery query, ReadStreamResult <HerculesEvent> streamResult, CancellationToken cancellationToken) =>
 streamEventsHandler.HandleAsync(query, streamResult.FromGenericResult(), cancellationToken);
        public async Task <(ReadStreamQuery query, ReadStreamResult <T> result)> ReadAsync(
            StreamCoordinates coordinates,
            StreamShardingSettings shardingSettings,
            CancellationToken cancellationToken)
        {
            log.Info(
                "Reading logical shard with index {ClientShard} from {ClientShardCount}.",
                shardingSettings.ClientShardIndex,
                shardingSettings.ClientShardCount);

            log.Debug("Current coordinates: {StreamCoordinates}.", coordinates);

            coordinates = await GetShardCoordinates(coordinates, shardingSettings, cancellationToken).ConfigureAwait(false);

            log.Debug("Current shard coordinates: {StreamCoordinates}.", coordinates);

            streamPartitionsCount = streamPartitionsCount ?? await GetPartitionsCount(cancellationToken).ConfigureAwait(false);

            var current = coordinates.ToDictionary();

            foreach (var partition in coordinates.Positions.Select(p => p.Partition))
            {
                var start = current.ContainsKey(partition) ? current[partition].Offset : 0;
                var end   = settings.End.ContainsKey(partition) ? settings.End[partition].Offset : 0;

                if (start < end)
                {
                    var count = end - start;

                    log.Info("Reading {EventsCount} events from partition #{Partition}.", count, partition);

                    var(query, result) = await streamReader.ReadAsync(
                        coordinates,
                        // ReSharper disable once PossibleInvalidOperationException
                        new StreamShardingSettings(partition, streamPartitionsCount.Value),
                        count,
                        cancellationToken)
                                         .ConfigureAwait(false);

                    result.EnsureSuccess();

                    result = new ReadStreamResult <T>(
                        result.Status,
                        new ReadStreamPayload <T>(
                            result.Payload.Events,
                            coordinates.SetPosition(result.Payload.Next.Positions.Single())),
                        result.ErrorDetails);

                    query = new ReadStreamQuery(query.Name)
                    {
                        Coordinates      = coordinates,
                        ClientShard      = shardingSettings.ClientShardIndex,
                        ClientShardCount = shardingSettings.ClientShardCount
                    };

                    return(query, result);
                }
            }

            return(null, null);
        }