public MessageSequence <TMessage> Complete <TMessage>()
        {
            _logger.LogDebug($"Message Sequence for '{_globalMessageId}' completes with '{typeof(TMessage).Name}'.");
            var sequenceDef = _repository.GetOrCreate(_globalMessageId);

            var messageTcs = new TaskCompletionSource <TMessage>();
            var sequence   = new MessageSequence <TMessage>
            {
                Task = messageTcs.Task
            };

            sequenceDef.TaskCompletionSource.Task.ContinueWith(tObj =>
            {
                UpdateSequenceFinalState(sequence);
                messageTcs.TrySetResult((TMessage)tObj.Result);
            });

            Func <TMessage, TMessageContext, Task> func = (message, context) =>
            {
                Task
                .WhenAll(sequenceDef.State.HandlerTasks)
                .ContinueWith(t => sequenceDef.TaskCompletionSource.TrySetResult(message));
                return(Task.FromResult(true));
            };

            var bindTask = _chainTopology.BindToExchange <TMessage>(_globalMessageId);

            _dispatcher.AddMessageHandler(_globalMessageId, func);

            Task
            .WhenAll(bindTask)
            .ContinueWith(t => _publishAsync())
            .Unwrap()
            .Wait();

            Timer timeoutTimer = null;

            timeoutTimer = new Timer(state =>
            {
                timeoutTimer?.Dispose();
                var seq = _repository.Get(_globalMessageId);
                if (seq != null)
                {
                    seq.State.Aborted = true;
                    _repository.Update(seq);
                    UpdateSequenceFinalState(sequence);
                }

                messageTcs.TrySetException(
                    new TimeoutException(
                        $"Unable to complete sequence {_globalMessageId} in {_mainCfg.RequestTimeout.ToString("g")}. Operation Timed out."));
            }, null, _mainCfg.RequestTimeout, new TimeSpan(-1));

            return(sequence);
        }
        public void InvokeMessageHandler(Guid globalMessageId, object body, IMessageContext context)
        {
            var sequence = _sequenceRepository.Get(globalMessageId);

            if (sequence?.State.Aborted ?? true)
            {
                _logger.LogInformation($"Sequence for '{globalMessageId}' is either not found or aborted.");
                return;
            }
            var bodyType   = body.GetType();
            var invokedIds = Enumerable
                             .Concat(sequence.State.Completed, sequence.State.Skipped)
                             .Select(s => s.StepId);
            var last       = sequence.StepDefinitions.LastOrDefault();
            var notInvoked = sequence.StepDefinitions
                             .Where(s => !invokedIds.Contains(s.Id))
                             .Except(new [] { last })
                             .ToList();

            if (notInvoked.All(s => s.Optional))
            {
                notInvoked.Add(last);
            }

            var match = notInvoked.FirstOrDefault(p => p.Type == bodyType);

            if (match == last)
            {
                var skipped = notInvoked
                              .TakeWhile(p => p != match)
                              .Select(s => new ExecutionResult
                {
                    Time   = DateTime.Now,
                    Type   = s.Type,
                    StepId = s.Id
                })
                              .ToList();
                sequence.State.Skipped.AddRange(skipped);
                _logger.LogDebug($"Skipping {skipped.Count} message handlers for {globalMessageId}");
            }
            try
            {
                if (match == null)
                {
                    _logger.LogInformation($"Unable to find applicable message handler of type '{bodyType.Name}' for '{globalMessageId}'");
                    return;
                }
                _logger.LogInformation($"Invoking message handler of type '{bodyType.Name}' for '{globalMessageId}'");
                sequence.State.Completed.Add(new ExecutionResult
                {
                    Type   = bodyType,
                    Time   = DateTime.Now,
                    StepId = match.Id
                });
                sequence.State.HandlerTasks.Add(match.Handler(body, context));
            }
            catch (Exception e)
            {
                _logger.LogError($"Message handler of type '{bodyType.Name}' for '{globalMessageId}' threw an unhandles exception.", e);
                sequence.State.Aborted = true;
                sequence.TaskCompletionSource.TrySetException(e);
            }
            if (match.AbortsExecution)
            {
                _logger.LogInformation($"Message handler of type '{bodyType.Name}' for '{globalMessageId}' aborts execution.");
                sequence.State.Aborted = true;
                sequence.TaskCompletionSource.TrySetResult(null);
            }
        }