예제 #1
0
        /// <summary>
        /// Will at least try to process all queued system messages: in case of
        /// failure simply drop and go on to the next, because there is nothing to
        /// restart here (failure is in <see cref="ActorCell"/> somewhere …). In case the mailbox
        /// becomes closed (because of processing a <see cref="Terminate"/> message), dump all
        /// already dequeued message to deadLetters.
        /// </summary>
        private void ProcessAllSystemMessages()
        {
            Exception interruption = null;
            var       messageList  = SystemDrain(SystemMessageList.LNil);

            while (messageList.NonEmpty && !IsClosed())
            {
                var msg = messageList.Head;
                messageList = messageList.Tail;
                msg.Unlink();
                DebugPrint("{0} processing system message {1} with {2}", Actor.Self, msg, string.Join(",", Actor.GetChildren()));
                // we know here that SystemInvoke ensures that only "fatal" exceptions get rethrown
#if UNSAFE_THREADING
                try
                {
                    Actor.SystemInvoke(msg);
                }

                catch (ThreadInterruptedException ex)
                // thrown only if thread is explicitly interrupted, which should never happen
                {
                    interruption = ex;
                }
                catch (ThreadAbortException ex) // can be thrown if dispatchers shutdown / application terminates / etc
                {
                    interruption = ex;
                }
#else
                Actor.SystemInvoke(msg);
#endif

                // don't ever execute normal message when system message present!
                if (messageList.IsEmpty && !IsClosed())
                {
                    messageList = SystemDrain(SystemMessageList.LNil);
                }
            }

            /*
             * if we closed the mailbox, we must dump the remaining system messages
             * to deadLetters (this is essential for DeathWatch)
             */
            var dlm = Actor.Dispatcher.Mailboxes.DeadLetterMailbox;
            while (messageList.NonEmpty)
            {
                var msg = messageList.Head;
                messageList = messageList.Tail;
                msg.Unlink();
                try
                {
                    dlm.SystemEnqueue(Actor.Self, msg);
                }
#if UNSAFE_THREADING
                catch (ThreadInterruptedException ex)
                // thrown only if thread is explicitly interrupted, which should never happen
                {
                    interruption = ex;
                }
                catch (ThreadAbortException ex) // can be thrown if dispatchers shutdown / application terminates / etc
                {
                    interruption = ex;
                }
#endif
                catch (Exception ex)
                {
                    Actor.System.EventStream.Publish(new Error(ex, GetType().FullName, GetType(), $"error while enqueuing {msg} to deadletters: {ex.Message}"));
                }
            }

            // if we got an interruption while handling system messages, rethrow it
            if (interruption != null)
            {
                // no need to clear interrupted flag in CLR, unlike JVM
                throw interruption;
            }
        }