Пример #1
0
        private void CheckRemoteInbox(string key)
        {
            var inbox = this;
            var count = cluster.QueueLength(key);

            while (count > 0)
            {
                ActorInboxCommon.GetNextMessage(cluster, actor.Id, key).IfSome(
                    x => iter(x, (dto, msg) =>
                {
                    try
                    {
                        switch (msg.MessageType)
                        {
                        case Message.Type.System: ActorInboxCommon.SystemMessageInbox(actor, inbox, (SystemMessage)msg, parent); break;

                        case Message.Type.User: ActorInboxCommon.UserMessageInbox(actor, inbox, (UserControlMessage)msg, parent); break;

                        case Message.Type.UserControl: ActorInboxCommon.UserMessageInbox(actor, inbox, (UserControlMessage)msg, parent); break;
                        }
                    }
                    catch (Exception e)
                    {
                        ActorContext.WithContext(new ActorItem(actor, inbox, actor.Flags), parent, dto.Sender, msg as ActorRequest, msg, () => replyErrorIfAsked(e));
                        tell(ActorContext.DeadLetters, DeadLetter.create(dto.Sender, actor.Id, e, "Remote message inbox.", msg));
                        logSysErr(e);
                    }
                    finally
                    {
                        cluster.Dequeue <RemoteMessageDTO>(key);
                    }
                }));
                count--;
            }
        }
Пример #2
0
        public Option <T> PreProcessMessageContent(object message)
        {
            if (message == null)
            {
                tell(ActorContext.DeadLetters, DeadLetter.create(Sender, Self, "Message is null for tell (expected " + typeof(T) + ")", message));
                return(None);
            }

            if (typeof(T) != typeof(string) && message is string)
            {
                try
                {
                    // This allows for messages to arrive from JS and be dealt with at the endpoint
                    // (where the type is known) rather than the gateway (where it isn't)
                    return(Some(JsonConvert.DeserializeObject <T>((string)message)));
                }
                catch
                {
                    tell(ActorContext.DeadLetters, DeadLetter.create(Sender, Self, "Invalid message type for tell (expected " + typeof(T) + ")", message));
                    return(None);
                }
            }

            if (!typeof(T).IsAssignableFrom(message.GetType()))
            {
                tell(ActorContext.DeadLetters, DeadLetter.create(Sender, Self, "Invalid message type for tell (expected " + typeof(T) + ")", message));
                return(None);
            }

            return(Some((T)message));
        }
Пример #3
0
        InboxDirective RunMessageDirective(
            ProcessId pid,
            ProcessId sender,
            StrategyDecision decision,
            Exception e,
            object message
            )
        {
            var directive = decision.MessageDirective;

            switch (directive.Type)
            {
            case MessageDirectiveType.ForwardToParent:
                tell(pid.Parent(), message, sender);
                return(InboxDirective.Default);

            case MessageDirectiveType.ForwardToSelf:
                tell(pid, message, sender);
                return(InboxDirective.Default);

            case MessageDirectiveType.ForwardToProcess:
                tell((directive as ForwardToProcess).ProcessId, message, sender);
                return(InboxDirective.Default);

            case MessageDirectiveType.StayInQueue:
                return(InboxDirective.PushToFrontOfQueue);

            default:
                tell(ActorContext.DeadLetters, DeadLetter.create(sender, pid, e, "Process error: ", message));
                return(InboxDirective.Default);
            }
        }
 /// <summary>
 /// Forward the current message to dead-letters (and wrap it in a contextual dead-letter
 /// structre)
 /// </summary>
 /// <param name="ex">Exception that caused the dead-letter</param>
 public static Unit dead(Exception ex, SystemName system = default(SystemName)) =>
 tell(
     ActorContext.System(system).DeadLetters,
     DeadLetter.create(
         Sender,
         Self,
         ex,
         ActorContext.Request.CurrentMsg
         ));
 /// <summary>
 /// Forward the current message to dead-letters (and wrap it in a contextual dead-letter
 /// structre)
 /// </summary>
 /// <param name="reason">Reason for the dead-letter</param>
 public static Unit dead(string reason, SystemName system = default(SystemName)) =>
 tell(
     ActorContext.System(system).DeadLetters,
     DeadLetter.create(
         Sender,
         Self,
         reason,
         ActorContext.Request.CurrentMsg
         ));
 /// <summary>
 /// Forward a message to dead-letters (and wrap it in a contextual dead-letter
 /// structre)
 /// </summary>
 /// <param name="message">Dead letter message</param>
 /// <param name="ex">Exception that caused the dead-letter</param>
 public static Unit dead(object message, Exception ex, SystemName system = default(SystemName)) =>
 tell(
     ActorContext.System(system).DeadLetters,
     DeadLetter.create(
         Sender,
         Self,
         ex,
         message
         ));
 /// <summary>
 /// Forward the current message to dead-letters (and wrap it in a contextual dead-letter
 /// structre)
 /// </summary>
 /// <param name="ex">Exception that caused the dead-letter</param>
 public static Unit dead(Exception ex) =>
 tell(
     ActorContext.DeadLetters,
     DeadLetter.create(
         Sender,
         Self,
         ex,
         ActorContext.CurrentMsg
         ));
 /// <summary>
 /// Forward the current message to dead-letters (and wrap it in a contextual dead-letter
 /// structre)
 /// </summary>
 /// <param name="reason">Reason for the dead-letter</param>
 public static Unit dead(string reason) =>
 tell(
     ActorContext.DeadLetters,
     DeadLetter.create(
         Sender,
         Self,
         reason,
         ActorContext.CurrentMsg
         ));
 /// <summary>
 /// Forward a message to dead-letters (and wrap it in a contextual dead-letter
 /// structre)
 /// </summary>
 /// <param name="message">Dead letter message</param>
 /// <param name="ex">Exception that caused the dead-letter</param>
 public static Unit dead(object message, Exception ex) =>
 tell(
     ActorContext.DeadLetters,
     DeadLetter.create(
         Sender,
         Self,
         ex,
         message
         ));
 /// <summary>
 /// Forward a message to dead-letters (and wrap it in a contextual dead-letter
 /// structre)
 /// </summary>
 /// <param name="message">Dead letter message</param>
 /// <param name="reason">Reason for the dead-letter</param>
 public static Unit dead(object message, string reason) =>
 tell(
     ActorContext.DeadLetters,
     DeadLetter.create(
         Sender,
         Self,
         reason,
         message
         ));
 /// <summary>
 /// Forward a message to dead-letters (and wrap it in a contextual dead-letter
 /// structre)
 /// </summary>
 /// <param name="message">Dead letter message</param>
 /// <param name="reason">Reason for the dead-letter</param>
 public static Unit dead(object message, string reason, SystemName system = default(SystemName)) =>
 tell(
     ActorContext.System(system).DeadLetters,
     DeadLetter.create(
         Sender,
         Self,
         reason,
         message
         ));
        void CheckRemoteInbox(string key, bool pausable)
        {
            var inbox = this;
            var count = cluster?.QueueLength(key) ?? 0;

            while (count > 0 && (!pausable || !IsPaused))
            {
                var directive = InboxDirective.Default;

                ActorInboxCommon.GetNextMessage(cluster, actor.Id, key).IfSome(
                    x => iter(x, (dto, msg) =>
                {
                    try
                    {
                        switch (msg.MessageType)
                        {
                        case Message.Type.User:        directive = ActorInboxCommon.UserMessageInbox(actor, inbox, (UserControlMessage)msg, parent); break;

                        case Message.Type.UserControl: directive = ActorInboxCommon.UserMessageInbox(actor, inbox, (UserControlMessage)msg, parent); break;
                        }
                    }
                    catch (Exception e)
                    {
                        var session = msg.SessionId == null
                                ? None
                                : Some(new SessionId(msg.SessionId));

                        ActorContext.System(actor.Id).WithContext(new ActorItem(actor, inbox, actor.Flags), parent, dto.Sender, msg as ActorRequest, msg, session, () => replyErrorIfAsked(e));
                        tell(ActorContext.System(actor.Id).DeadLetters, DeadLetter.create(dto.Sender, actor.Id, e, "Remote message inbox.", msg));
                        logSysErr(e);
                    }
                    finally
                    {
                        if ((directive & InboxDirective.Pause) != 0)
                        {
                            IsPaused  = true;
                            directive = directive & (~InboxDirective.Pause);
                        }

                        if (directive == InboxDirective.Default)
                        {
                            cluster?.Dequeue <RemoteMessageDTO>(key);
                        }
                    }
                }));

                if (directive == InboxDirective.Default)
                {
                    count--;
                }
            }
        }
Пример #13
0
        public static Option <Tuple <RemoteMessageDTO, Message> > GetNextMessage(ICluster cluster, ProcessId self, string key)
        {
            if (cluster == null)
            {
                return(None);
            }
            Message          msg = null;
            RemoteMessageDTO dto = null;

            dto = null;
            do
            {
                dto = cluster.Peek <RemoteMessageDTO>(key);
                if (dto == null)
                {
                    // Queue is empty
                    return(None);
                }
                if (dto.Tag == 0 && dto.Type == 0)
                {
                    // Message is bad
                    cluster.Dequeue <RemoteMessageDTO>(key);
                    tell(ActorContext.System(self).DeadLetters, DeadLetter.create(dto.Sender, self, null, "Failed to deserialise message: ", dto));
                    if (cluster.QueueLength(key) == 0)
                    {
                        return(None);
                    }
                }
            }while (dto == null || dto.Tag == 0 || dto.Type == 0);

            try
            {
                msg           = MessageSerialiser.DeserialiseMsg(dto, self);
                msg.SessionId = dto.SessionId;
            }
            catch (Exception e)
            {
                // Message can't be deserialised
                cluster.Dequeue <RemoteMessageDTO>(key);
                tell(ActorContext.System(self).DeadLetters, DeadLetter.create(dto.Sender, self, e, "Failed to deserialise message: ", msg));
                return(None);
            }

            return(Some(Tuple(dto, msg)));
        }
Пример #14
0
 private FSharpMailboxProcessor <TMsg> StartMailbox <TMsg>(Actor <S, T> actor, string key, CancellationToken cancelToken, Action <Actor <S, T>, IActorInbox, TMsg, ActorItem> handler)
     where TMsg : Message =>
 ActorInboxCommon.Mailbox <TMsg>(cancelToken, msg =>
 {
     try
     {
         handler(actor, this, msg, parent);
     }
     catch (Exception e)
     {
         replyErrorIfAsked(e);
         tell(ActorContext.DeadLetters, DeadLetter.create(ActorContext.Sender, actor.Id, e, "Remote message inbox.", msg));
         logSysErr(e);
     }
     finally
     {
         // Remove from queue, then see if there are any more to process.
         CheckRemoteInbox(key, cluster, actor.Id, sysInbox, userInbox);
     }
 });
Пример #15
0
 FSharpMailboxProcessor <TMsg> StartMailbox <TMsg>(Actor <S, T> actor, string key, CancellationToken cancelToken, Func <Actor <S, T>, IActorInbox, TMsg, ActorItem, InboxDirective> handler, bool pausable)
     where TMsg : Message =>
 ActorInboxCommon.Mailbox <TMsg>(cancelToken, msg =>
 {
     try
     {
         var directive = handler(actor, this, msg, parent);
         // TODO: Push msg to front of queue if directive requests it
     }
     catch (Exception e)
     {
         replyErrorIfAsked(e);
         tell(ActorContext.System(actor.Id).DeadLetters, DeadLetter.create(ActorContext.Request.Sender, actor.Id, e, "Remote message inbox.", msg));
         logSysErr(e);
     }
     finally
     {
         // Remove from queue, then see if there are any more to process.
         CheckRemoteInbox(key, cluster, actor.Id, sysInbox, userInbox, pausable);
     }
 });
        /// <summary>
        /// TODO: This is a combination of code in ActorCommon.GetNextMessage and
        ///       CheckRemoteInbox.  Some factoring is needed.
        /// </summary>
        void SysInbox(RemoteMessageDTO dto)
        {
            try
            {
                if (dto == null)
                {
                    // Failed to deserialise properly
                    return;
                }
                if (dto.Tag == 0 && dto.Type == 0)
                {
                    // Message is bad
                    tell(ActorContext.System(actor.Id).DeadLetters, DeadLetter.create(dto.Sender, actor.Id, null, "Failed to deserialise message: ", dto));
                    return;
                }
                var msg = MessageSerialiser.DeserialiseMsg(dto, actor.Id);

                try
                {
                    lock (sync)
                    {
                        ActorInboxCommon.SystemMessageInbox(actor, this, (SystemMessage)msg, parent);
                    }
                }
                catch (Exception e)
                {
                    var session = msg.SessionId == null
                        ? None
                        : Some(new SessionId(msg.SessionId));

                    ActorContext.System(actor.Id).WithContext(new ActorItem(actor, this, actor.Flags), parent, dto.Sender, msg as ActorRequest, msg, session, () => replyErrorIfAsked(e));
                    tell(ActorContext.System(actor.Id).DeadLetters, DeadLetter.create(dto.Sender, actor.Id, e, "Remote message inbox.", msg));
                    logSysErr(e);
                }
            }
            catch (Exception e)
            {
                logSysErr(e);
            }
        }
        public static Option <UserControlMessage> PreProcessMessage <T>(ProcessId sender, ProcessId self, object message)
        {
            if (message == null)
            {
                var emsg = $"Message is null for tell (expected {typeof(T)})";
                tell(ActorContext.DeadLetters, DeadLetter.create(sender, self, emsg, message));
                return(None);
            }

            if (message is ActorRequest)
            {
                var req = (ActorRequest)message;
                if (!(req.Message is T) && !(req.Message is Message))
                {
                    var emsg = $"Invalid message type for ask (expected {typeof(T)})";
                    tell(ActorContext.DeadLetters, DeadLetter.create(sender, self, emsg, message));

                    ActorContext.Tell(
                        sender,
                        new ActorResponse(new Exception($"Invalid message type for ask (expected {typeof(T)})"),
                                          typeof(Exception).AssemblyQualifiedName,
                                          sender,
                                          self,
                                          req.RequestId,
                                          true
                                          ),
                        self
                        );

                    return(None);
                }
                return(Optional((UserControlMessage)message));
            }

            return(new UserMessage(message, sender, sender));
        }
Пример #18
0
        /// <summary>
        /// Process an inbox message
        /// </summary>
        /// <param name="message"></param>
        /// <returns></returns>
        public Unit ProcessMessage(object message)
        {
            var savedReq   = ActorContext.CurrentRequest;
            var savedFlags = ActorContext.ProcessFlags;
            var savedMsg   = ActorContext.CurrentMsg;

            try
            {
                ActorContext.CurrentRequest = null;
                ActorContext.ProcessFlags   = flags;
                ActorContext.CurrentMsg     = message;

                if (typeof(T) != typeof(string) && message is string)
                {
                    state = PreProcessMessageContent(message).Match(
                        Some: tmsg =>
                    {
                        var stateIn  = GetState();
                        var stateOut = actorFn(stateIn, tmsg);
                        try
                        {
                            if (stateOut != null && !stateOut.Equals(stateIn))
                            {
                                stateSubject.OnNext(state);
                            }
                        }
                        catch (Exception ue)
                        {
                            logErr(ue);
                        }
                        return(stateOut);
                    },
                        None: () => state
                        );
                }
                else if (message is T)
                {
                    var s = actorFn(GetState(), (T)message);
                    state = s;
                    try
                    {
                        stateSubject.OnNext(state);
                    }
                    catch (Exception ue)
                    {
                        logErr(ue);
                    }
                }
                else if (message is Message)
                {
                    ProcessSystemMessage((Message)message);
                }
                else
                {
                    logErr("ProcessMessage request.Message is not T " + message);
                }
            }
            catch (SystemKillActorException)
            {
                logInfo("Process message - system kill " + Id);
                kill(Id);
            }
            catch (Exception e)
            {
                // TODO: Add extra strategy behaviours here
                Restart();
                tell(ActorContext.Errors, e);
                tell(ActorContext.DeadLetters, DeadLetter.create(Sender, Self, e, "Process error (tell): ", message));
            }
            finally
            {
                ActorContext.CurrentRequest = savedReq;
                ActorContext.ProcessFlags   = savedFlags;
                ActorContext.CurrentMsg     = savedMsg;
            }
            return(unit);
        }
Пример #19
0
        public Unit ProcessAsk(ActorRequest request)
        {
            var savedMsg   = ActorContext.CurrentMsg;
            var savedFlags = ActorContext.ProcessFlags;
            var savedReq   = ActorContext.CurrentRequest;

            try
            {
                ActorContext.CurrentRequest = request;
                ActorContext.ProcessFlags   = flags;
                ActorContext.CurrentMsg     = request.Message;

                if (typeof(T) != typeof(string) && request.Message is string)
                {
                    state = PreProcessMessageContent(request.Message).Match(
                        Some: tmsg =>
                    {
                        var stateIn  = GetState();
                        var stateOut = actorFn(stateIn, tmsg);
                        try
                        {
                            if (stateOut != null && !stateOut.Equals(stateIn))
                            {
                                stateSubject.OnNext(stateOut);
                            }
                        }
                        catch (Exception ue)
                        {
                            logErr(ue);
                        }
                        return(stateOut);
                    },
                        None: () => state
                        );
                }
                else if (request.Message is T)
                {
                    T   msg      = (T)request.Message;
                    var stateIn  = GetState();
                    var stateOut = actorFn(stateIn, msg);
                    try
                    {
                        if (stateOut != null && !stateOut.Equals(stateIn))
                        {
                            stateSubject.OnNext(stateOut);
                        }
                    }
                    catch (Exception ue)
                    {
                        logErr(ue);
                    }
                    state = stateOut;
                }
                else if (request.Message is Message)
                {
                    ProcessSystemMessage((Message)request.Message);
                }
                else
                {
                    logErr("ProcessAsk request.Message is not T " + request.Message);
                }
            }
            catch (SystemKillActorException)
            {
                kill(Id);
            }
            catch (Exception e)
            {
                // TODO: Add extra strategy behaviours here
                Restart();
                replyError(e);
                tell(ActorContext.Errors, e);
                tell(ActorContext.DeadLetters, DeadLetter.create(request.ReplyTo, request.To, e, "Process error (ask): ", request.Message));
            }
            finally
            {
                ActorContext.CurrentMsg     = savedMsg;
                ActorContext.ProcessFlags   = savedFlags;
                ActorContext.CurrentRequest = savedReq;
            }
            return(unit);
        }