예제 #1
0
        async Task Dispatch(CapturedTransportOperation operation, RootContext rootContext)
        {
            using (var conn = settings.Links[operation.Destination].ConnectionFactory())
            {
                await conn.OpenAsync().ConfigureAwait(false);

                using (var trans = conn.BeginTransaction())
                {
                    //Will block until the record insert transaction is completed.
                    await OutboxPersister.MarkAsDispatched(operation, conn, trans).ConfigureAwait(false);

                    var iface = settings.GetDestinationInterface(operation.Destination);

                    var chains          = rootContext.Interfaces.GetChainsFor(iface);
                    var chain           = chains.Get <AnycastContext>();
                    var dispatchContext = new OutboxDispatchContext(rootContext, iface);
                    var forwardContext  = new AnycastContext(operation.Destination, operation.OutgoingMessage, DistributionStrategyScope.Send, dispatchContext);
                    dispatchContext.Set(new TransportTransaction());
                    await chain.Invoke(forwardContext).ConfigureAwait(false);

                    //Only commit the transaction if the dispatch succeeded.
                    trans.Commit();
                }
            }
        }
예제 #2
0
        public async Task Store(CapturedTransportOperation operation, Action triggerAdvance, SqlConnection conn, SqlTransaction trans)
        {
            var localState = linkState;

            var seq = await sequence.GetNextValue(conn, trans).ConfigureAwait(false);

            InterlocedEx.ExchangeIfGreaterThan(ref highestSeq, seq);

            if (localState.IsStale(seq))
            {
                var freshLinkState = await linkStateTable.Get(operation.Destination, conn, trans).ConfigureAwait(false);

                UpdateCachedLinkState(freshLinkState);
                localState = linkState;
            }

            if (localState.ShouldAdvance(seq))
            {
                triggerAdvance();
            }

            if (localState.IsStale(seq))
            {
                throw new ProcessCurrentMessageLaterException("Link state is stale. Processing current message later.");
            }

            var tableName = localState.GetTableName(seq);
            var table     = new OutboxTable(tableName);

            try
            {
                operation.OutgoingMessage.Headers[RouterDeduplicationHeaders.SequenceNumber] = seq.ToString();
                operation.OutgoingMessage.Headers[RouterDeduplicationHeaders.SequenceKey]    = sourceKey;
                operation.AssignTable(tableName);
                operation.AssignSequence(seq);

                var persistentOperation = Convert(operation);

                await table.Insert(persistentOperation, seq, conn, trans).ConfigureAwait(false);
            }
            catch (SqlException e)
            {
                if (e.Number == 547) //Constraint violation. We used very old seq and that value cannot be used any more because the epoch has advanced.
                {
                    var freshLinkState = await linkStateTable.Get(operation.Destination, conn, trans).ConfigureAwait(false);

                    UpdateCachedLinkState(freshLinkState);
                    throw new ProcessCurrentMessageLaterException("Link state is stale. Processing current message later.");
                }
                throw;
            }
            catch (Exception ex)
            {
                log.Debug($"Unhandled exception while storing outbox operation with sequence {seq}", ex);
                throw;
            }
        }
 public Task Store(CapturedTransportOperation operation, SqlConnection conn, SqlTransaction trans)
 {
     return(persisters[operation.Destination].Store(operation, conn, trans));
 }
예제 #4
0
 public void Enqueue(CapturedTransportOperation operation)
 {
     operationsQueue.Add(operation);
 }
 public Task Store(CapturedTransportOperation operation, SqlConnection conn, SqlTransaction trans)
 {
     return(persister.Store(operation, () => @event.Set(), conn, trans));
 }