Esempio n. 1
0
        internal override void ProcessCallbacks(object ctx, RedisResult result)
        {
            RedisResult[] subItems;
            if (!result.IsError && (subItems = result.ValueItems) != null)
            {
                switch (subItems.Length)
                {
                case 3:
                    RedisResult msgType = subItems[0];
                    if (msgType.IsMatch(message))
                    {
                        string key = subItems[1].ValueString;
                        OnMessageReceived(key, key, subItems[2]);
                    }
                    else if (msgType.IsMatch(subscribe) || msgType.IsMatch(unsubscribe) ||
                             msgType.IsMatch(psubscribe) || msgType.IsMatch(punsubscribe))
                    {
                        var newCount = (int)subItems[2].ValueInt64;
                        Interlocked.Exchange(ref subscriptionCount, newCount);
                    }
                    break;

                case 4:
                    if (subItems[0].IsMatch(pmessage))
                    {
                        OnMessageReceived(subItems[1].ValueString, subItems[2].ValueString, subItems[3]);
                    }
                    break;
                }
            }
        }
Esempio n. 2
0
        void IMultiMessage.Execute(RedisConnectionBase conn, ref int currentDb)
        {
            var pending = messages;

            if (ExecutePreconditions(conn, ref currentDb))
            {
                conn.WriteRaw(this);                                                         // MULTI
                List <QueuedMessage> newlyQueued = new List <QueuedMessage>(pending.Length); // estimate same length
                for (int i = 0; i < pending.Length; i++)
                {
                    conn.WriteMessage(ref currentDb, pending[i], newlyQueued);
                }
                newlyQueued.TrimExcess();
                conn.WriteMessage(ref currentDb, Execute(newlyQueued), null);
            }
            else
            {
                // preconditions failed; ABORT
                conn.WriteMessage(ref currentDb, RedisMessage.Create(-1, RedisLiteral.UNWATCH).ExpectOk().Critical(), null);

                // even though these weren't written, we still need to mark them cancelled
                exec.Abort(pending);
                // spoof a rollback; same appearance to the caller
                exec.Complete(RedisResult.Multi(null), false);
            }
        }
 internal override void Complete(RedisResult result)
 {
     received = DateTime.UtcNow;
     base.Complete(result.IsError
                       ? result
                       : new RedisResult.TimingRedisResult(
                       sent - created, received - sent));
 }
Esempio n. 4
0
        protected virtual void ProcessError(RedisResult result, RedisMessage message, bool includeDetail)
        {
            var ex = result.Error();

            if (message != null && includeDetail)
            {
                ex.Data.Add("redis-command", message.ToString());
            }
            source.SafeSetException(ex);
        }
 internal void CancelUnsent()
 {
     RedisMessage[] all = unsent.DequeueAll();
     for (int i = 0; i < all.Length; i++)
     {
         RedisResult result = RedisResult.Cancelled;
         object      ctx    = ProcessReply(ref result, all[i]);
         ProcessCallbacks(ctx, result);
     }
 }
 internal void CompleteMessage(RedisMessage message, RedisResult result)
 {
     try
     {
         message.Complete(result);
     }
     catch (Exception ex)
     {
         OnError("Completing message", ex, false);
     }
 }
Esempio n. 7
0
        internal virtual void Complete(RedisResult result, bool includeDetail)
        {
            RedisConnectionBase.Trace("completed", "~ {0}", command);
            var snapshot = Interlocked.Exchange(ref messageResult, null); // only run once

            ChangeState(MessageState.Sent, MessageState.Complete);
            if (snapshot != null)
            {
                snapshot.Complete(result, this, includeDetail);
            }
        }
        internal virtual void Complete(RedisResult result)
        {
#if VERBOSE
            Trace.WriteLine("< " + command);
#endif
            IMessageResult snapshot = Interlocked.Exchange(ref messageResult, null); // only run once
            ChangeState(MessageState.Sent, MessageState.Complete);
            if (snapshot != null)
            {
                snapshot.Complete(result);
            }
        }
 private void SetInnerReplies(RedisResult result)
 {
     if (queued != null)
     {
         for (int i = 0; i < queued.Length; i++)
         {
             RedisResult reply = result; // need to be willing for this to be mutated
             object      ctx   = parent.ProcessReply(ref reply, queued[i].InnerMessage);
             parent.ProcessCallbacks(ctx, reply);
         }
     }
 }
Esempio n. 10
0
        void IMessageResult.Complete(RedisResult result, RedisMessage message, bool includeDetail)
        {
            if (result.IsCancellation)
            {
                RedisConnectionBase.Trace("transaction", "cancelled");
                SetInnerReplies(result);
                completion.TrySetCanceled();
            }
            else if (result.IsError)
            {
                RedisConnectionBase.Trace("transaction", "error");
                SetInnerReplies(result);
                completion.SafeSetException(result.Error());
            }
            else
            {
                try
                {
                    if (result.IsNil)
                    {   // aborted
                        RedisConnectionBase.Trace("transaction", "aborted");
                        SetInnerReplies(RedisResult.Cancelled);
                        completion.TrySetResult(false);
                    }
                    else
                    {
                        var items = result.ValueItems;
                        if (items.Length != (queued == null ? 0 : queued.Length))
                        {
                            throw new InvalidOperationException(string.Format("{0} results expected, {1} received", queued.Length, items.Length));
                        }

                        RedisConnectionBase.Trace("transaction", "success");
                        for (int i = 0; i < items.Length; i++)
                        {
                            RedisResult reply = items[i];
                            RedisConnectionBase.CallbackMode callbackMode;
                            var ctx = parent.ProcessReply(ref reply, queued[i].InnerMessage, out callbackMode);
                            RedisConnectionBase.Trace("transaction", "{0} = {1}", ctx, reply);
                            parent.ProcessCallbacks(ctx, reply, callbackMode);
                        }
                        completion.TrySetResult(true);
                    }
                }
                catch (Exception ex)
                {
                    completion.SafeSetException(ex);
                    throw;
                }
            }
        }
Esempio n. 11
0
 void SetInnerReplies(RedisResult result)
 {
     if (queued != null)
     {
         for (int i = 0; i < queued.Length; i++)
         {
             var reply = result; // need to be willing for this to be mutated
             RedisConnectionBase.CallbackMode callbackMode;
             var ctx = parent.ProcessReply(ref reply, queued[i].InnerMessage, out callbackMode);
             RedisConnectionBase.Trace("transaction", "{0} = {1}", ctx, reply);
             parent.ProcessCallbacks(ctx, reply, callbackMode);
         }
     }
 }
Esempio n. 12
0
 protected override void ProcessError(RedisResult result, RedisMessage message, bool includeDetail)
 {
     try {
         var msg = result.Error().Message;
         if (msg.StartsWith("NOSCRIPT"))
         {   // only way of unloading is to unload all ("SCRIPT FLUSH")... so our
             // existing cache is now completely toast
             connection.ResetScriptCache();
         }
     } catch {
         /* best efforts only */
     }
     base.ProcessError(result, message, includeDetail);
 }
        void IMessageResult.Complete(RedisResult result)
        {
            if (result.IsCancellation)
            {
                completion.SetCanceled();
                SetInnerReplies(result);
            }
            else if (result.IsError)
            {
                completion.SetException(result.Error());
                SetInnerReplies(result);
            }
            else
            {
                try
                {
                    if (result.IsNil)
                    {
                        // aborted
                        SetInnerReplies(RedisResult.Cancelled);
                        completion.SetResult(false);
                    }
                    else
                    {
                        RedisResult[] items = result.ValueItems;
                        if (items.Length != (queued == null ? 0 : queued.Length))
                        {
                            throw new InvalidOperationException(string.Format("{0} results expected, {1} received",
                                                                              queued.Length, items.Length));
                        }

                        for (int i = 0; i < items.Length; i++)
                        {
                            RedisResult reply = items[i];
                            object      ctx   = parent.ProcessReply(ref reply, queued[i].InnerMessage);
                            parent.ProcessCallbacks(ctx, reply);
                        }
                        completion.SetResult(true);
                    }
                }
                catch (Exception ex)
                {
                    completion.SetException(ex);
                    throw;
                }
            }
        }
        private void Outgoing()
        {
            try
            {
                OnOpened();
                int          db = 0;
                RedisMessage next;
                Trace.WriteLine("Redis send-pump is starting");
                bool isHigh, shouldFlush;
                while (unsent.TryDequeue(false, out next, out isHigh, out shouldFlush))
                {
                    if (abort)
                    {
                        CompleteMessage(next, RedisResult.Error("The system aborted before this message was sent"));
                        continue;
                    }
                    if (!next.ChangeState(MessageState.NotSent, MessageState.Sent))
                    {
                        // already cancelled; not our problem any more...
                        Interlocked.Increment(ref messagesCancelled);
                        continue;
                    }
                    if (isHigh)
                    {
                        Interlocked.Increment(ref queueJumpers);
                    }
                    WriteMessage(ref db, next, null);
                    Flush(shouldFlush);
                }
                Interlocked.CompareExchange(ref state, (int)ConnectionState.Closing, (int)ConnectionState.Open);
                if (redisStream != null)
                {
                    RedisMessage quit = RedisMessage.Create(-1, RedisLiteral.QUIT).ExpectOk().Critical();

                    RecordSent(quit, !abort);
                    quit.Write(outBuffer);
                    outBuffer.Flush();
                    redisStream.Flush();
                    Interlocked.Increment(ref messagesSent);
                }
                Trace.WriteLine("Redis send-pump is exiting");
            }
            catch (Exception ex)
            {
                OnError("Outgoing queue", ex, true);
            }
        }
Esempio n. 15
0
        internal override object ProcessReply(ref RedisResult result, RedisMessage message)
        {
            byte[] expected;
            if (!result.IsError && (expected = message.Expected) != null)
            {
                result = result.IsMatch(expected)
                             ? RedisResult.Pass
                             : RedisResult.Error(result.ValueString);
            }


            if (result.IsError && message.MustSucceed)
            {
                throw new RedisException("A critical operation failed: " + message);
            }
            return(message);
        }
 private void RaiseEvent(Action <string, byte[]> handler, string key, RedisResult value)
 {
     if (handler == null)
     {
         return;
     }
     foreach (Action <string, byte[]> child in handler.GetInvocationList())
     {
         try
         {
             child(key, value.ValueBytes);
         }
         catch (Exception ex)
         {
             OnError("Subscriber callback", ex, false);
         }
     }
 }
Esempio n. 17
0
        internal override object ProcessReply(ref RedisResult result)
        {
            RedisMessage message;

            lock (sent)
            {
                int count = sent.Count;
                if (count == 0)
                {
                    throw new RedisException("Data received with no matching message");
                }
                message = sent.Dequeue();
                if (count == 1)
                {
                    Monitor.Pulse(sent); // in case the outbound stream is closing and needs to know we're up-to-date
                }
            }
            return(ProcessReply(ref result, message));
        }
        internal override void ProcessCallbacksImpl(object ctx, RedisResult result)
        {
            RedisResult[] subItems;
            bool          callBase = true;

            if (!result.IsError && (subItems = result.ValueItems) != null)
            {
                switch (subItems.Length)
                {
                case 3:
                    var msgType = subItems[0];
                    if (msgType.IsMatch(message))
                    {
                        string key = subItems[1].ValueString;
                        OnMessageReceived(key, key, subItems[2]);
                        callBase = false;
                    }
                    else if (msgType.IsMatch(subscribe) || msgType.IsMatch(unsubscribe) ||
                             msgType.IsMatch(psubscribe) || msgType.IsMatch(punsubscribe))
                    {
                        int newCount = (int)subItems[2].ValueInt64;
                        Interlocked.Exchange(ref subscriptionCount, newCount);
                    }
                    break;

                case 4:
                    if (subItems[0].IsMatch(pmessage))
                    {
                        OnMessageReceived(subItems[1].ValueString, subItems[2].ValueString, subItems[3]);
                        callBase = false;
                    }
                    break;
                }
            }

            if (ctx != null && callBase) // don't call down to the base for things that aren't related to outbound messages
            {
                base.ProcessCallbacksImpl(ctx, result);
            }
        }
        void IMultiMessage.Execute(RedisConnectionBase conn, ref int currentDb)
        {
            RedisMessage[] pending       = messages;
            int            estimateCount = pending.Length;

            if (ExecutePreconditions(conn, ref currentDb))
            {
                conn.WriteRaw(this); // MULTI
                var newlyQueued = new List <QueuedMessage>(pending.Length);
                for (int i = 0; i < pending.Length; i++)
                {
                    conn.WriteMessage(ref currentDb, pending[i], newlyQueued);
                }
                newlyQueued.TrimExcess();
                conn.WriteMessage(ref currentDb, Execute(newlyQueued), null);
            }
            else
            {
                // preconditions failed; ABORT
                conn.WriteMessage(ref currentDb, Create(-1, RedisLiteral.UNWATCH).ExpectOk().Critical(), null);
                exec.Complete(RedisResult.Multi(null)); // spoof a rollback; same appearance to the caller
            }
        }
        internal override object ProcessReply(ref RedisResult result, out CallbackMode callbackMode)
        {
            RedisResult[] subItems;
            if (!result.IsError && (subItems = result.ValueItems) != null)
            {
                // detect "message" and "pmessage" and don't dequeue for those
                switch (subItems.Length)
                {
                case 3:     // special-case message
                    if (subItems[0].IsMatch(message))
                    {
                        callbackMode = CallbackMode.Continuation;     // events are a lot like continuations
                        return(null);
                    }
                    break;

                case 4:     // special-case pmessage
                    if (subItems[0].IsMatch(pmessage))
                    {
                        callbackMode = CallbackMode.Continuation;     // events are a lot like continuations
                        return(null);
                    }
                    break;
                }
            }

            var next = PeekSent(false) as IMultiReplyMessage;

            if (next == null || next.Consume())
            {
                return(base.ProcessReply(ref result, out callbackMode));
            }
            // if we get here, we are dealing with a multi-reply message that is not yet satisfied; do nothing
            callbackMode = CallbackMode.SyncUnchecked; // won't actually be doing anything
            return(null);
        }
Esempio n. 21
0
        /// <summary>
        ///     Invoked when the server is terminating
        /// </summary>
        protected override void ShuttingDown(Exception error)
        {
            base.ShuttingDown(error);
            RedisMessage message;
            RedisResult  result = null;

            lock (sent)
            {
                if (sent.Count > 0)
                {
                    result = RedisResult.Error(
                        error == null
                            ? "The server terminated before a reply was received"
                            : ("Error processing data: " + error.Message));
                }
                while (sent.Count > 0)
                {
                    // notify clients of things that just didn't happen

                    message = sent.Dequeue();
                    CompleteMessage(message, result);
                }
            }
        }
Esempio n. 22
0
 protected override bool GetValue(RedisResult result)
 {
     result.Assert(); return(true);
 }
Esempio n. 23
0
 protected override Dictionary <string, string> GetValue(RedisResult result)
 {
     return(result.ExtractStringPairs());
 }
Esempio n. 24
0
 internal override void Complete(RedisResult result, bool includeDetail)
 {
     throw new NotSupportedException();
 }
 private void RaiseEvent(Action<string, byte[]> handler, string key, RedisResult value)
 {
     if (handler == null) return;
     foreach (Action<string, byte[]> child in handler.GetInvocationList())
     {
         try
         {
             child(key, value.ValueBytes);
         }
         catch (Exception ex)
         {
             OnError("Subscriber callback", ex, false);
         }
     }
 }
 private void OnMessageReceived(string subscriptionKey, string messageKey, RedisResult value)
 {
     ProcessNamedSubscription(subscriptionKey, messageKey, value);
     RaiseEvent(MessageReceived, messageKey, value);
 }
Esempio n. 27
0
 void SetInnerReplies(RedisResult result)
 {
     if (queued != null)
     {
         for (int i = 0; i < queued.Length; i++)
         {
             var reply = result; // need to be willing for this to be mutated
             RedisConnectionBase.CallbackMode callbackMode;
             var ctx = parent.ProcessReply(ref reply, queued[i].InnerMessage, out callbackMode);
             RedisConnectionBase.Trace("transaction", "{0} = {1}", ctx, reply);
             parent.ProcessCallbacks(ctx, reply, callbackMode);
         }
     }
 }
Esempio n. 28
0
 protected override double  GetValue(RedisResult result)
 {
     return(result.ValueDouble);
 }
Esempio n. 29
0
        void IMessageResult.Complete(RedisResult result)
        {
            if (result.IsCancellation)
            {
                completion.SetCanceled();
            }
            else if (result.IsError)
            {
                completion.SetException(result.Error());
            }
            else
            {
                try
                {
                    if (queued == null) throw new InvalidOperationException("Nothing was queued (null)!");
                    var items = result.ValueItems;
                    if (items.Length != queued.Length) throw new InvalidOperationException(string.Format("{0} results expected, {1} received", queued.Length, items.Length));

                    for (int i = 0; i < items.Length; i++)
                    {
                        RedisResult reply = items[i];
                        var ctx = parent.ProcessReply(ref reply, queued[i].InnerMessage);
                        parent.ProcessCallbacks(ctx, reply);
                    }
                    completion.SetResult(true);
                }
                catch (Exception ex)
                {
                    completion.SetException(ex);
                    throw;
                }
            }
        }
Esempio n. 30
0
 internal override void Complete(RedisResult result)
 {
     // do nothing - this is just the WATCH; we'll spoof the reply manually from the multi-message reply
 }
Esempio n. 31
0
 internal virtual void Complete(RedisResult result)
 {
     #if VERBOSE
     Trace.WriteLine("< " + command);
     #endif
     var snapshot = Interlocked.Exchange(ref messageResult, null); // only run once
     ChangeState(MessageState.Sent, MessageState.Complete);
     if (snapshot != null)
     {
         snapshot.Complete(result);
     }
 }
Esempio n. 32
0
 internal virtual void Complete(RedisResult result, bool includeDetail)
 {
     RedisConnectionBase.Trace("completed", "~ {0}", command);
     var snapshot = Interlocked.Exchange(ref messageResult, null); // only run once
     ChangeState(MessageState.Sent, MessageState.Complete);
     if (snapshot != null)
     {
         snapshot.Complete(result, this, includeDetail);
     }
 }
Esempio n. 33
0
 internal override void Complete(RedisResult result, bool includeDetail)
 {
     received = DateTime.UtcNow;
     base.Complete(result.IsError ? result : new RedisResult.TimingRedisResult(
         sent - created, received - sent), includeDetail);
 }
Esempio n. 34
0
        protected override bool GetValue(RedisResult result)
        {
            var items = result.ValueItems;

            return(items != null);
        }
Esempio n. 35
0
 protected override long?GetValue(RedisResult result)
 {
     return(result.IsNil ? (long?)null : (long?)result.ValueInt64);
 }
Esempio n. 36
0
 protected abstract T GetValue(RedisResult result);
 internal override object ProcessReply(ref RedisResult result)
 {
     return ProcessReply(ref result, null);
 }
Esempio n. 38
0
 protected override long GetValue(RedisResult result)
 {
     return(result.ValueInt64);
 }
Esempio n. 39
0
        void IMessageResult.Complete(RedisResult result, RedisMessage message, bool includeDetail)
        {
            if (result.IsCancellation)
            {
                RedisConnectionBase.Trace("transaction", "cancelled");
                SetInnerReplies(result);
                completion.TrySetCanceled();
            }
            else if (result.IsError)
            {
                RedisConnectionBase.Trace("transaction", "error");
                SetInnerReplies(result);
                completion.SafeSetException(result.Error());
            }
            else
            {
                try
                {
                    if (result.IsNil)
                    {   // aborted
                        RedisConnectionBase.Trace("transaction", "aborted");
                        SetInnerReplies(RedisResult.Cancelled);
                        completion.TrySetResult(false);
                    }
                    else
                    {
                        var items = result.ValueItems;
                        if (items.Length != (queued == null ? 0 : queued.Length))
                            throw new InvalidOperationException(string.Format("{0} results expected, {1} received", queued.Length, items.Length));

                        RedisConnectionBase.Trace("transaction", "success");
                        for (int i = 0; i < items.Length; i++)
                        {
                            RedisResult reply = items[i];
                            RedisConnectionBase.CallbackMode callbackMode;
                            var ctx = parent.ProcessReply(ref reply, queued[i].InnerMessage, out callbackMode);
                            RedisConnectionBase.Trace("transaction", "{0} = {1}", ctx, reply);
                            parent.ProcessCallbacks(ctx, reply, callbackMode);
                        }
                        completion.TrySetResult(true);
                    }
                }
                catch (Exception ex)
                {
                    completion.SafeSetException(ex);
                    throw;
                }
            }
        }
 internal override void ProcessCallbacks(object ctx, RedisResult result)
 {
     RedisResult[] subItems;
     if (!result.IsError && (subItems = result.ValueItems) != null)
     {
         switch (subItems.Length)
         {
             case 3:
                 RedisResult msgType = subItems[0];
                 if (msgType.IsMatch(message))
                 {
                     string key = subItems[1].ValueString;
                     OnMessageReceived(key, key, subItems[2]);
                 }
                 else if (msgType.IsMatch(subscribe) || msgType.IsMatch(unsubscribe)
                          || msgType.IsMatch(psubscribe) || msgType.IsMatch(punsubscribe))
                 {
                     var newCount = (int) subItems[2].ValueInt64;
                     Interlocked.Exchange(ref subscriptionCount, newCount);
                 }
                 break;
             case 4:
                 if (subItems[0].IsMatch(pmessage))
                 {
                     OnMessageReceived(subItems[1].ValueString, subItems[2].ValueString, subItems[3]);
                 }
                 break;
         }
     }
 }
Esempio n. 41
0
 public MultiRedisResult(RedisResult[] items)
 {
     this.items = items;
 }
 internal override object ProcessReply(ref RedisResult result, RedisMessage message)
 {
     return null;
 }
Esempio n. 43
0
 internal override object ProcessReply(ref RedisResult result)
 {
     RedisMessage message;
     lock (sent)
     {
         int count = sent.Count;
         if (count == 0) throw new RedisException("Data received with no matching message");
         message = sent.Dequeue();
         if (count == 1) Monitor.Pulse(sent); // in case the outbound stream is closing and needs to know we're up-to-date
     }
     return ProcessReply(ref result, message);
 }
 private void ProcessNamedSubscription(string subscriptionKey, string messageKey, RedisResult value)
 {
     if (string.IsNullOrEmpty(subscriptionKey)) return;
     Action<string, byte[]> handler;
     lock (subscriptions)
     {
         if (!subscriptions.TryGetValue(subscriptionKey, out handler)) handler = null;
     }
     RaiseEvent(handler, messageKey, value);
 }
 private void SetInnerReplies(RedisResult result)
 {
     if (queued != null)
     {
         for (int i = 0; i < queued.Length; i++)
         {
             RedisResult reply = result; // need to be willing for this to be mutated
             object ctx = parent.ProcessReply(ref reply, queued[i].InnerMessage);
             parent.ProcessCallbacks(ctx, reply);
         }
     }
 }
Esempio n. 46
0
 internal static RedisResult Multi(RedisResult[] inner)
 {
     return new MultiRedisResult(inner);
 }
Esempio n. 47
0
 protected override Dictionary <string, byte[]> GetValue(RedisResult result)
 {
     return(result.ExtractHashPairs());
 }
Esempio n. 48
0
 internal override void ProcessCallbacks(object ctx, RedisResult result)
 {
     CompleteMessage((RedisMessage)ctx, result);
 }
Esempio n. 49
0
 protected override KeyValuePair <string, double>[] GetValue(RedisResult result)
 {
     return(result.ExtractStringDoublePairs());
 }
Esempio n. 50
0
        internal override object ProcessReply(ref RedisResult result, RedisMessage message)
        {
            byte[] expected;
            if (!result.IsError && (expected = message.Expected) != null)
            {
                result = result.IsMatch(expected)
                ? RedisResult.Pass : RedisResult.Error(result.ValueString);
            }

            if (result.IsError && message.MustSucceed)
            {
                throw new RedisException("A critical operation failed: " + message.ToString());
            }
            return message;
        }
        void IMessageResult.Complete(RedisResult result)
        {
            if (result.IsCancellation)
            {
                completion.SetCanceled();
                SetInnerReplies(result);
            }
            else if (result.IsError)
            {
                completion.SetException(result.Error());
                SetInnerReplies(result);
            }
            else
            {
                try
                {
                    if (result.IsNil)
                    {
                        // aborted
                        SetInnerReplies(RedisResult.Cancelled);
                        completion.SetResult(false);
                    }
                    else
                    {
                        RedisResult[] items = result.ValueItems;
                        if (items.Length != (queued == null ? 0 : queued.Length))
                            throw new InvalidOperationException(string.Format("{0} results expected, {1} received",
                                                                              queued.Length, items.Length));

                        for (int i = 0; i < items.Length; i++)
                        {
                            RedisResult reply = items[i];
                            object ctx = parent.ProcessReply(ref reply, queued[i].InnerMessage);
                            parent.ProcessCallbacks(ctx, reply);
                        }
                        completion.SetResult(true);
                    }
                }
                catch (Exception ex)
                {
                    completion.SetException(ex);
                    throw;
                }
            }
        }