簡體   English   中英

第二條消息在我的Akka.Net演員中變得未處理,然后似乎停止了

[英]Second message becomes Unhandled in my Akka.Net actor and then it seems to halt

免責聲明:我是Akka的新手:)

我正在嘗試在Akka中實現一個路由器

  1. 收到一條消息
  2. 在字典中查找用於處理消息類型的IActorRef
  3. 如果找不到匹配項,則使用Akka.DI作為子演員創建一個並添加到字典中
  4. 轉發消息給那個演員

這很好用-第一次,但是如果我兩次嘗試對路由器進行Tell()或Ask(),則第二條消息總是以未處理的形式出現在流中

我嘗試在子actor中覆蓋Unhandled()並在其中放置一個斷點,實際上這是第二條消息被擊中的原因。

路由器:

public class CommandRouter : UntypedActor
{
    protected readonly IActorResolver _resolver;
    private static readonly Dictionary<Type, IActorRef> _routees = new Dictionary<Type, IActorRef>();
    private ILoggingAdapter _log = Context.GetLogger(new SerilogLogMessageFormatter());

    public CommandRouter(IActorResolver resolver)
    {
        _resolver = resolver;
    }

    protected override void OnReceive(object message)
    {
        _log.Info("Routing command {cmd}", message);
        var typeKey = message.GetType();

        if (!_routees.ContainsKey(typeKey))
        {
            var props = CreateActorProps(typeKey);

            if (!props.Any())
            {
                Sender?.Tell(Response.WithException(
                    new RoutingException(
                        $"Could not route message to routee. No routees found for message type {typeKey.FullName}")));
                return;
            }

            if (props.Count() > 1)
            {
                Sender?.Tell(Response.WithException(
                    new RoutingException(
                        $"Multiple routees registered for message {typeKey.FullName}, which is not supported by this router. Did you want to publish stuff instead?")));
                return;
            }

            var prop = props.First();
            var routee = Context.ActorOf(prop, prop.Type.Name);
            _routees.Add(typeKey, routee);
        }

        _routees[typeKey].Forward(message);

    }

    private IEnumerable<Props> CreateActorProps(Type messageType)
    {
        return _resolver.TryCreateActorProps(typeof(IHandleCommand<>).MakeGenericType(messageType)).ToList();
    }

    protected override SupervisorStrategy SupervisorStrategy()
    {
        return new OneForOneStrategy(x => Directive.Restart);
    }
}

ActorResolver方法,使用來自Akka.DI.StructureMap的DependencyResolver:

public IEnumerable<Props> TryCreateActorProps(Type actorType)
{
    foreach (var type in _container.GetAllInstances(actorType))
    {
        yield return _resolver.Create(type.GetType());
    }
}

實際的兒童演員非常有前途:

public class ProductSubscriptionHandler : ReceiveActor, IHandleCommand<AddProductSubscription>
{
    public ProductSubscriptionHandler()
    {
        Receive<AddProductSubscription>(Handle);
    }

    protected bool Handle(AddProductSubscription command)
    {
        Sender?.Tell(Response.Empty);
        return true;
    }
}

在actor系統初始化之后,整個過程將被調用,如下所示:

var router = Sys.ActorOf(resolver.Create<CommandRouter>(), ActorNames.CommandRouter);

router.Ask(new AddProductSubscription());
router.Ask(new AddProductSubscription());

我在第二(或任何后續)消息中始終收到此錯誤:“來自...的未處理消息”:

[INFO][17-07-2017 23:05:39][Thread 0003][[akka://pos-system/user/CommandRouter#676182398]] Routing command Commands.AddProductSubscription
[DEBUG][17-07-2017 23:05:39][Thread 0003][akka://pos-system/user/CommandRouter] now supervising akka://pos-system/user/CommandRouter/ProductSubscriptionHandler
[DEBUG][17-07-2017 23:05:39][Thread 0003][akka://pos-system/user/CommandRouter] *Unhandled message from akka://pos-system/temp/d* : Documents.Commands.AddProductSubscription
[DEBUG][17-07-2017 23:05:39][Thread 0007][akka://pos-system/user/CommandRouter/ProductSubscriptionHandler] Started (Consumers.Service.Commands.ProductSubscriptionHandler)

因此,事實證明,有一個比我的問題更簡單(有效)的解決方案:只需在CommandRouter構造函數中注冊並啟動所有路由參與者,而不是按接收即可。

所以現在我的代碼看起來也簡單得多:

CommandRouter:

public class CommandRouterActor : UntypedActor
{
    public Dictionary<Type, IActorRef> RoutingTable { get; }
    private ILoggingAdapter _log = Context.GetLogger(new SerilogLogMessageFormatter());

    public CommandRouterActor(IActorResolver resolver)
    {
        var props = resolver.CreateCommandHandlerProps();
        RoutingTable = props.ToDictionary(k => k.Item1, v => Context.ActorOf(v.Item2, $"CommandHandler-{v.Item1.Name}"));
    }

    protected override void OnReceive(object message)
    {
        _log.Info("Routing command {cmd}", message);
        var typeKey = message.GetType();

        if (!RoutingTable.ContainsKey(typeKey))
        {
                Sender?.Tell(Response.WithException(
                    new RoutingException(
                        $"Could not route message to routee. No routees found for message type {typeKey.FullName}")));

                _log.Info("Could not route command {cmd}, no routes found", message);
        }

        RoutingTable[typeKey].Forward(message);
    }

    protected override SupervisorStrategy SupervisorStrategy()
    {
        return new OneForOneStrategy(x => Directive.Restart);
    }
}

我的ActorResolver (在上面的ctor中使用)僅查詢StructureMap模型並詢問 IHandleCommand<> 所有已注冊實例

    public IEnumerable<Tuple<Type, Props>> CreateCommandHandlerProps()
    {
        var handlerTypes =
            _container.Model.AllInstances.Where(
                    i =>
                        i.PluginType.IsGenericType && i.PluginType.GetGenericTypeDefinition() ==
                        typeof(IHandleCommand<>))
                .Select(m => m.PluginType);

        foreach (var handler in handlerTypes)
        {
            yield return new Tuple<Type, Props>(handler.GenericTypeArguments.First(), _resolver.Create(handler));
        }
    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM