Ejemplo n.º 1
0
        private static async Task ProcessEvents(ThreadParam param, DelayedClient client, ResolvedEvent[] events)
        {
            // A fake message that will travel through the pipeline in order to bulk process messages from the context bag
            var bulkMarker = new BulkMessage().Serialize(param.JsonSettings).AsByteArray();

            var delayed = events.Select(x => x.Event.Data.Deserialize <DelayedMessage>(param.JsonSettings)).ToArray();

            Logger.Write(LogLevel.Info, () => $"Processing {delayed.Count()} bulk events on stream {events.First().Event.EventStreamId}");

            var contextBag = new ContextBag();

            // Hack to get all the delayed messages to bulk invoker without NSB deserializing and processing each one
            contextBag.Set(Defaults.BulkHeader, delayed);

            // Run bulk process on this thread
            using (var tokenSource = new CancellationTokenSource())
            {
                var success = false;
                var retry   = 0;
                do
                {
                    var transportTransaction = new TransportTransaction();

                    // Need to supply EnclosedMessageTypes to trick NSB pipeline into processing our fake message
                    var messageId = Guid.NewGuid().ToString();
                    var headers   = new Dictionary <string, string>()
                    {
                        [Headers.EnclosedMessageTypes] = typeof(BulkMessage).AssemblyQualifiedName,
                        [Headers.MessageIntent]        = MessageIntentEnum.Send.ToString(),
                        [Headers.MessageId]            = messageId,
                        [Defaults.BulkHeader]          = delayed.Count().ToString(),
                    };

                    try
                    {
                        // If canceled, this will throw the number of time immediate retry requires to send the message to the error queue
                        param.Token.ThrowIfCancellationRequested();

                        // Don't re-use the event id for the message id
                        var messageContext = new NServiceBus.Transport.MessageContext(messageId,
                                                                                      headers,
                                                                                      bulkMarker, transportTransaction, tokenSource,
                                                                                      contextBag);
                        await Bus.OnMessage(messageContext).ConfigureAwait(false);//param.Token);

                        Logger.Write(LogLevel.Debug,
                                     () => $"Scheduling acknowledge of {delayed.Count()} bulk events");
                        DelayedCount.Increment(delayed.Count());
                        client.Acknowledge(events);
                        success = true;
                    }
                    catch (ObjectDisposedException)
                    {
                        // NSB transport has been disconnected
                        break;
                    }
                    catch (Exception e)
                    {
                        DelayedErrors.Mark($"{e.GetType().Name} {e.Message}");
                    }


                    retry++;
                } while (!success && retry <= param.MaxRetry);

                if (!success)
                {
                    // Dont run through NSB's error handler, it expects a single serialized message which
                    // is not compatible here.  Just tell EventStore to retry it
                    // Todo: ES will park messages that fail - develop something to monitor parked messages
                    client.Nack(events);
                }
            }
        }
Ejemplo n.º 2
0
        public Task Subscribe(CancellationToken cancelToken)
        {
            _cancelation = CancellationTokenSource.CreateLinkedTokenSource(cancelToken);
            var stream = $"$ce-{_endpoint}.{StreamTypes.Delayed}";
            var group  = $"{_endpoint}.{Assembly.GetEntryAssembly().GetName().Version}.{StreamTypes.Delayed}.ROUND";

            Task.Run(async() =>
            {
                while (Bus.OnMessage == null || Bus.OnError == null)
                {
                    Logger.Warn($"Could not find NSBs onMessage handler yet - if this persists there is a problem.");
                    await Task.Delay(1000, cancelToken).ConfigureAwait(false);
                }


                var settings = PersistentSubscriptionSettings.Create()
                               .StartFromBeginning()
                               .WithMaxRetriesOf(10)
                               .WithReadBatchOf(_readsize)
                               .WithLiveBufferSizeOf(_readsize * _readsize)
                               //.WithMessageTimeoutOf(TimeSpan.FromMilliseconds(int.MaxValue))
                               .WithMessageTimeoutOf(TimeSpan.FromMinutes(1))
                               .CheckPointAfter(TimeSpan.FromSeconds(30))
                               .MaximumCheckPointCountOf(_readsize * _readsize)
                               .ResolveLinkTos()
                               .WithNamedConsumerStrategy(SystemConsumerStrategies.Pinned);
                if (_extraStats)
                {
                    settings.WithExtraStatistics();
                }

                var clients = new DelayedClient[_clients.Count()];

                for (var i = 0; i < _clients.Count(); i++)
                {
                    var client = _clients.ElementAt(i);

                    var clientCancelSource = CancellationTokenSource.CreateLinkedTokenSource(_cancelation.Token);

                    client.Closed += (object s, ClientClosedEventArgs args) =>
                    {
                        Logger.Info($"Eventstore disconnected - shutting down delayed subscription");
                        clientCancelSource.Cancel();
                    };
                    try
                    {
                        await
                        client.CreatePersistentSubscriptionAsync(stream, group, settings,
                                                                 client.Settings.DefaultUserCredentials).ConfigureAwait(false);
                        Logger.Info($"Created ROUND ROBIN persistent subscription to stream [{stream}]");
                    }
                    catch (InvalidOperationException)
                    {
                    }

                    clients[i] = new DelayedClient(client, stream, group, _maxDelayed, clientCancelSource.Token);
                }
                _delayedThread = new Thread(Threaded)
                {
                    IsBackground = true, Name = $"Delayed Event Thread"
                };
                _delayedThread.Start(new ThreadParam {
                    Token = cancelToken, Clients = clients, JsonSettings = _settings, MaxRetry = _maxRetry
                });
            });

            return(Task.CompletedTask);
        }