protected async Task OnReceiveMessageAsync(EntityActorMessage message) { if (message == null) { throw new ArgumentNullException(nameof(message)); } if (!isInitialized) { //Only 1 thread ever will call OnInternalReceiveMessageAsync but it prevents //any external initialization from happening. lock (SyncObj) { if (!isInitialized) { if (ExtractPotentialStateMessage(message, out var initMessage)) { InitializeState(initMessage.State); //Send successful initialization message to the entity, immediately. //Some entities may not care. OnInitialized(new EntityActorInitializationSuccessMessage()); } else { if (Logger.IsWarnEnabled) { Logger.Warn($"{GetType().Name} encountered MessageType: {message.GetType().Name} before INITIALIZATION."); } } //Even if we're initialized now, it's an init message we shouldn't continue with. return; } } } //TODO: Is it safe to capture the Context message ref forever?? //TODO: Pool or cache somehow. EntityActorMessageContext context = new EntityActorMessageContext(Context); try { if (!await HandleMessageAsync(message, context)) { if (Logger.IsWarnEnabled) { Logger.Warn($"EntityActor encountered unhandled MessageType: {message.GetType().Name}"); } } } catch (Exception e) { if (Logger.IsErrorEnabled) { Logger.Error($"Actor: {Self.Path.Address} failed to handle MessageType: {message.GetType().Name} without Exception: {e.Message}\n\nStack: {e.StackTrace}"); } throw; } }
private bool TrySendMessage(object message) { EntityActorMessage castedMessage = (EntityActorMessage)message; EntityActorMessageContext context = new EntityActorMessageContext(Sender, Self, Context.System.Scheduler); return(MessageRouter.RouteMessage(context, ActorState, castedMessage)); }
/// <summary> /// Implementer can override the behavior of extracting the state from the provided initialization message. /// </summary> /// <param name="message"></param> /// <param name="entityActorStateInitializeMessage"></param> /// <returns></returns> protected virtual bool ExtractPotentialStateMessage(EntityActorMessage message, out EntityActorStateInitializeMessage <TActorStateType> entityActorStateInitializeMessage) { if (message is EntityActorStateInitializeMessage <TActorStateType> initMessage) { entityActorStateInitializeMessage = initMessage; return(true); } entityActorStateInitializeMessage = null; return(false); }
/// <summary> /// Implements must override this and implement domain-specific message handling logic. /// </summary> /// <param name="message">The message to handle.</param> /// <param name="context">The actor message context.</param> /// <returns>True if the message was successfully handled.</returns> protected Task <bool> HandleMessageAsync(EntityActorMessage message, EntityActorMessageContext context) { if (message == null) { throw new ArgumentNullException(nameof(message)); } if (context == null) { throw new ArgumentNullException(nameof(context)); } return(MessageHandlerService.HandleMessageAsync(context, message, CancellationToken.None)); }
/// <summary> /// See Akka.NET's <see cref="IActorRef"/>.Tell. /// Sends self with <see cref="actorReference"/> as the sender. /// </summary> /// <param name="actorReference"></param> /// <param name="message"></param> public static void TellSelf(this IActorRef actorReference, EntityActorMessage message) { if (actorReference == null) { throw new ArgumentNullException(nameof(actorReference)); } if (message == null) { throw new ArgumentNullException(nameof(message)); } actorReference.Tell((object)message, actorReference); }
public bool RouteMessage(EntityActorMessageContext messageContext, TEntityActorStateType state, EntityActorMessage message) { if (messageContext == null) { throw new ArgumentNullException(nameof(messageContext)); } if (state == null) { throw new ArgumentNullException(nameof(state)); } if (message == null) { throw new ArgumentNullException(nameof(message)); } if (EntityHandlerMap.ContainsKey(message.GetType())) { foreach (var handler in EntityHandlerMap[message.GetType()]) { handler.HandleMessage(messageContext, state, message); } return(true); } else { return(false); } }
public void HandleMessage(EntityActorMessageContext messageContext, TEntityStateType state, EntityActorMessage message) { //Assume caller has verified this will work //We downcast so the API consumed is simplier/easier. //We need the interface to not be specific so it can be discovered, registered and handled. HandleMessage(messageContext, state, (TEntityMessageType)message); }
public BroadcastTargeted(EntityActorMessage message, IActorRef target) : base(message) { Target = target ?? throw new ArgumentNullException(nameof(target)); }
public static void TellEntityChildren(this IActorRefFactory selector, EntityActorMessage message) { selector .ActorSelection(MEAKKASelectionConstants.ALL_DIRECT_CHILDREN_SELECTOR) .TellEntitySelection(message); }
public static void TellEntitySelection(this ActorSelection selection, EntityActorMessage message, IEntityActorRef sender) { TellEntitySelection(selection, message, sender.Actor); }
public static void TellEntitySelection(this ActorSelection selection, EntityActorMessage message, IActorRef sender) { selection .Tell(message, sender); }
public static void TellEntitySelection(this ActorSelection selection, EntityActorMessage message) { selection .Tell(message); }
public static void TellEntityChildren(this IActorRefFactory selector, EntityActorMessage message, IEntityActorRef sender) { TellEntityChildren(selector, message, sender.Actor); }
/// <inheritdoc /> public async Task <bool> HandleMessageAsync(EntityActorMessageContext context, EntityActorMessage message, CancellationToken token = default) { //We don't lock here even though dictionary is publicly mutable //But we discourage calling it. if (!MessageHandlerMap.ContainsKey(message.GetType())) { return(false); } foreach (var handler in MessageHandlerMap[message.GetType()]) { await handler.HandleMessageAsync(context, message, token); } return(true); }