Esempio n. 1
0
        public async Task WriteEvents <TEntity>(string bucket, Id streamId, Id[] parents, IFullEvent[] events, IDictionary <string, string> commitHeaders) where TEntity : IEntity
        {
            Logger.Write(LogLevel.Debug, $"Writing {events.Length} oob events stream [{streamId}] bucket [{bucket}]");
            await events.WhenAllAsync(async @event =>
            {
                var message = new FullMessage
                {
                    Message = @event.Event,
                    Headers = @event.Descriptor.Headers
                };

                var parentsStr = parents?.Any() ?? false ? parents.Aggregate <Id, string>("", (cur, next) => $"{cur},{next}") : "";

                var headers = new Dictionary <string, string>()
                {
                    [$"{Defaults.PrefixHeader}.EventId"]    = @event.EventId.ToString(),
                    [$"{Defaults.PrefixHeader}.EntityType"] = @event.Descriptor.EntityType,
                    [$"{Defaults.PrefixHeader}.Timestamp"]  = @event.Descriptor.Timestamp.ToString("yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture),
                    [$"{Defaults.PrefixHeader}.Version"]    = @event.Descriptor.Version.ToString(),
                    [$"{Defaults.PrefixHeader}.Bucket"]     = bucket,
                    [$"{Defaults.PrefixHeader}.StreamId"]   = streamId,
                    [$"{Defaults.PrefixHeader}.Parents"]    = parentsStr
                };

                string id = "";

                id = @event.Descriptor.Headers[Defaults.OobHeaderKey];

                if (@event.Descriptor.Headers.ContainsKey(Defaults.OobTransientKey) && bool.TryParse(@event.Descriptor.Headers[Defaults.OobTransientKey], out var transient) && !transient)
                {
                    var stream  = _generator(typeof(TEntity), StreamTypes.OOB, $"{id}.{bucket}", streamId, parents);
                    var version = await _store.WriteEvents(stream, new[] { @event }, headers).ConfigureAwait(false);
                    if (@event.Descriptor.Headers.ContainsKey(Defaults.OobDaysToLiveKey) && int.TryParse(@event.Descriptor.Headers[Defaults.OobDaysToLiveKey], out var daysToLive) && daysToLive != -1)
                    {
                        var key = $"{bucket}.{id}.{streamId}.{parentsStr}";
                        // Uses the dictionary to keep track of daysToLive data its already saved.
                        // If an entity saves the same stream with a new daysToLive the stream metadata needs to be rewritten
                        if (!DaysToLiveKnowns.ContainsKey(key) || DaysToLiveKnowns[key] != daysToLive)
                        {
                            DaysToLiveKnowns[key] = daysToLive;
                            await _store.WriteMetadata(stream, maxAge: TimeSpan.FromDays(daysToLive)).ConfigureAwait(false);
                        }
                    }
                }
                else
                {
                    await _dispatcher.Publish(message, headers).ConfigureAwait(false);
                }
            }).ConfigureAwait(false);
        }
Esempio n. 2
0
        public override async Task Invoke(IIncomingLogicalMessageContext context, Func <Task> next)
        {
            var messageId = context.MessageId;
            var retries   = 0;

            try
            {
                RetryRegistry.TryRemove(messageId, out retries);
                context.Headers[Defaults.Retries] = retries.ToString();
                context.Extensions.Set(Defaults.Retries, retries);

                await next().ConfigureAwait(false);
            }
            catch (Exception e)
            {
                // Special exception we dont want to retry or reply
                if (e is BusinessException || context.MessageHandled)
                {
                    return;
                }

                if (retries < _retries || _retries == -1)
                {
                    Logger.LogEvent((retries > _retries / 2) ? LogLevel.Warn : LogLevel.Info, "Catch", e, "[{MessageId:l}] will retry {Retries}/{MaxRetries}: {ExceptionType} - {ExceptionMessage}", messageId,
                                    retries, _retries, e.GetType().Name, e.Message);

                    RetryRegistry.TryAdd(messageId, retries + 1);

                    var message = new FullMessage
                    {
                        Message = context.Message.Instance as Messages.IMessage,
                        Headers = context.Headers
                    };

                    // todo: Not ideal for this to be here -
                    // but unpacking these headers takes place further down the queue after UOW start
                    // I don't want to start a new unit of work for each message in a bulk message (defeats the purpose)
                    // So need to do something a little special here
                    if (context.Extensions.TryGet(Defaults.BulkHeader, out IFullMessage[] delayedMessages))
Esempio n. 3
0
        private static void Threaded(object state)
        {
            var param = (ThreadParam)state;

            var container = Configuration.Settings.Container;

            var metrics    = container.Resolve <IMetrics>();
            var consumer   = container.Resolve <IEventStoreConsumer>();
            var dispatcher = container.Resolve <IMessageDispatcher>();


            try
            {
                while (true)
                {
                    param.Token.ThrowIfCancellationRequested();

                    var @event = WaitingEvents.Take(param.Token);
                    metrics.Decrement("Events Queued", Unit.Event);

                    try
                    {
                        var message = new FullMessage
                        {
                            Message = @event.Item3.Event,
                            Headers = @event.Item3.Descriptor.Headers
                        };

                        var headers =
                            new Dictionary <string, string>()
                        {
                            [$"{Defaults.PrefixHeader}.EventId"]       = @event.Item3.EventId.ToString(),
                            [$"{Defaults.PrefixHeader}.EventStream"]   = @event.Item1,
                            [$"{Defaults.PrefixHeader}.EventPosition"] = @event.Item2.ToString()
                        };

                        dispatcher.SendLocal(message, headers).ConfigureAwait(false).GetAwaiter().GetResult();

                        consumer.Acknowledge(@event.Item1, @event.Item2, @event.Item3).ConfigureAwait(false)
                        .GetAwaiter().GetResult();
                    }
                    catch (System.AggregateException e)
                    {
                        if (e.InnerException is OperationCanceledException)
                        {
                            throw e.InnerException;
                        }

                        // If not a canceled exception, just write to log and continue
                        // we dont want some random unknown exception to kill the whole event loop
                        Logger.ErrorEvent("Exception", e, "From event thread: {ExceptionType} - {ExceptionMessage}", e.GetType().Name, e.Message);
                    }
                }
            }
            catch (Exception e)
            {
                if (!(e is OperationCanceledException))
                {
                    Logger.ErrorEvent("Died", e, "Event thread closed: {ExceptionType} - {ExceptionMessage}", e.GetType().Name, e.Message);
                }
            }
        }
Esempio n. 4
0
        private static void Threaded(object state)
        {
            var param = (ThreadParam)state;

            var container = Configuration.Settings.Container;

            var metrics    = container.Resolve <IMetrics>();
            var consumer   = container.Resolve <IEventStoreConsumer>();
            var dispatcher = container.Resolve <IMessageDispatcher>();


            try
            {
                while (true)
                {
                    param.Token.ThrowIfCancellationRequested();

                    var @event = param.Queue.Take(param.Token);
                    metrics.Decrement("Events Queued", Unit.Event);

                    try
                    {
                        var message = new FullMessage
                        {
                            Message = @event.Item3.Event,
                            Headers = @event.Item3.Descriptor.Headers
                        };

                        var headers =
                            new Dictionary <string, string>()
                        {
                            [$"{Defaults.EventPrefixHeader}.EventId"]       = @event.Item3.EventId.ToString(),
                            [$"{Defaults.EventPrefixHeader}.EventStream"]   = @event.Item1,
                            [$"{Defaults.EventPrefixHeader}.EventPosition"] = @event.Item2.ToString()
                        };

                        dispatcher.SendLocal(message, headers).ConfigureAwait(false).GetAwaiter().GetResult();

                        Logger.Write(LogLevel.Debug,
                                     () => $"Acknowledge event {@event.Item3.Descriptor.EventId} stream [{@event.Item1}] number {@event.Item2}");
                        consumer.Acknowledge(@event.Item1, @event.Item2, @event.Item3).ConfigureAwait(false)
                        .GetAwaiter().GetResult();
                    }
                    catch (System.AggregateException e)
                    {
                        if (e.InnerException is OperationCanceledException)
                        {
                            throw e.InnerException;
                        }

                        // If not a canceled exception, just write to log and continue
                        // we dont want some random unknown exception to kill the whole event loop
                        Logger.Error($"Received exception in main event thread: {e.GetType()}: {e.Message}\n{e.AsString()}");
                    }
                }
            }
            catch (Exception e)
            {
                Logger.Error($"Event subscriber thread terminated due to exception: {e.GetType()}: {e.Message}\n{e.AsString()}");
            }
        }