Dependency injection Akka.DI.Autofac没有创建actor

Dependency injection Akka.DI.Autofac没有创建actor,dependency-injection,autofac,akka.net,Dependency Injection,Autofac,Akka.net,我正在尝试设置DI,后面是正式的akka.net文档()。然而,演员从不创造。下面我的代码有什么问题 public class Worker: ReceiveActor { public Worker() { Receive<string>(m => Console.WriteLine("Worker is working")); } } public class WorkerManager : ReceiveActor { p

我正在尝试设置DI,后面是正式的akka.net文档()。然而,演员从不创造。下面我的代码有什么问题

public class Worker: ReceiveActor
{
    public Worker()
    {
        Receive<string>(m => Console.WriteLine("Worker is working"));
    }
}

public class WorkerManager : ReceiveActor
{
    public WorkerManager()
    {
        Receive<string>(m => Console.WriteLine("Manager start supervise"));
    }

    protected override void PreStart()
    {
        Context.ActorOf(Context.DI().Props<Worker>(), "Worker1");
    }
}

class Program
{
    static void Main(string[] args)
    {
        ContainerBuilder builder = new ContainerBuilder();
        builder.RegisterType<Worker>();
        builder.RegisterType<WorkerManager>();

        var system = ActorSystem.Create("DiTestSystem");

        IContainer container = builder.Build();
        IDependencyResolver resolver = new AutoFacDependencyResolver(container, system);
        var manageRef = system.ActorOf(system.DI().Props<WorkerManager>(), "Manager1");

        manageRef.Tell("Hello");
        system.ActorSelection("/user/Manager1/Worker1").Tell("Hello");

        Console.ReadLine();
    }
}
公共类工作人员:ReceiveActor
{
公职人员()
{
接收(m=>Console.WriteLine(“工人正在工作”);
}
}
公共类WorkerManager:ReceiveActor
{
公共WorkerManager()
{
接收(m=>Console.WriteLine(“管理器启动管理”);
}
受保护的覆盖无效预启动()
{
Context.ActorOf(Context.DI().Props(),“Worker1”);
}
}
班级计划
{
静态void Main(字符串[]参数)
{
ContainerBuilder=新的ContainerBuilder();
RegisterType();
RegisterType();
var system=ActorSystem.Create(“数据测试系统”);
IContainer容器=builder.Build();
IDependencyResolver解析器=新的AutoFacDependencyResolver(容器、系统);
var manageRef=system.ActorOf(system.DI().Props(),“Manager1”);
manageRef.Tell(“你好”);
system.ActorSelection(“/user/Manager1/Worker1”).Tell(“Hello”);
Console.ReadLine();
}
}
当运行代码时,我得到了这个

[信息][24/04/2017 1:50:11 AM][线程0006][akka://DiTestSystem/user/Manager1/Worker1]来自的消息字符串akka://DiTestSystem/deadLetters 到akka://DiTestSystem/user/Manager1/Worker1 没有交货。遇到1封死信。
Manager start supervise

我发现使用Autofac无法足够快地创建Actor

当我添加Thread.Sleep(20)时,最后,正确地创建了actor

static void Main(string[] args)
{
    ContainerBuilder builder = new ContainerBuilder();
    builder.RegisterType<WorkerManager>();
    builder.RegisterType<Worker>();

    var system = ActorSystem.Create("DiTestSystem");

    IContainer container = builder.Build();
    IDependencyResolver resolver = new AutoFacDependencyResolver(container, system);
    var manageRef = system.ActorOf(system.DI().Props<WorkerManager>(), "Manager1");

    Thread.Sleep(20); // ADDED THIS LINE
    manageRef.Tell("Hello");
    system.ActorSelection("/user/Manager1/Worker1").Tell("Hello");

    Console.ReadLine();
}
static void Main(字符串[]args)
{
ContainerBuilder=新的ContainerBuilder();
RegisterType();
RegisterType();
var system=ActorSystem.Create(“数据测试系统”);
IContainer容器=builder.Build();
IDependencyResolver解析器=新的AutoFacDependencyResolver(容器、系统);
var manageRef=system.ActorOf(system.DI().Props(),“Manager1”);
Thread.Sleep(20);//添加了这一行
manageRef.Tell(“你好”);
system.ActorSelection(“/user/Manager1/Worker1”).Tell(“Hello”);
Console.ReadLine();
}
我认为这是一个相当大的问题,因为这种方法不能保证参与者总是在睡眠时间创建/解决问题


我一直对这个问题持开放态度,因为我认为这不是一个正确的答案。

我发现,使用Autofac无法足够快地创建Actor

当我添加Thread.Sleep(20)时,最后,正确地创建了actor

static void Main(string[] args)
{
    ContainerBuilder builder = new ContainerBuilder();
    builder.RegisterType<WorkerManager>();
    builder.RegisterType<Worker>();

    var system = ActorSystem.Create("DiTestSystem");

    IContainer container = builder.Build();
    IDependencyResolver resolver = new AutoFacDependencyResolver(container, system);
    var manageRef = system.ActorOf(system.DI().Props<WorkerManager>(), "Manager1");

    Thread.Sleep(20); // ADDED THIS LINE
    manageRef.Tell("Hello");
    system.ActorSelection("/user/Manager1/Worker1").Tell("Hello");

    Console.ReadLine();
}
static void Main(字符串[]args)
{
ContainerBuilder=新的ContainerBuilder();
RegisterType();
RegisterType();
var system=ActorSystem.Create(“数据测试系统”);
IContainer容器=builder.Build();
IDependencyResolver解析器=新的AutoFacDependencyResolver(容器、系统);
var manageRef=system.ActorOf(system.DI().Props(),“Manager1”);
Thread.Sleep(20);//添加了这一行
manageRef.Tell(“你好”);
system.ActorSelection(“/user/Manager1/Worker1”).Tell(“Hello”);
Console.ReadLine();
}
我认为这是一个相当大的问题,因为这种方法不能保证参与者总是在睡眠时间创建/解决问题


我对这个问题持开放态度,因为我认为这不是一个正确的答案。

这里的问题是一个竞赛条件。无论是否使用DI容器创建参与者,都可能发生这种情况

当使用actor系统时,您需要记住所有事情都是异步发生的。您可以在将消息发送到
WorkerManager
参与者后继续编写代码,但这并不意味着消息实际上已被接收和处理。它实际上被发布到一个邮箱,以便参与者在准备就绪时在另一个线程上处理

如果您有一个
WorkerManager
actor,最好不要尝试直接访问
Worker
actor。就像在现实生活中一样,你通常会要求经理组织一些要做的工作,然后经理会依次决定需要哪些员工,并将必要的工作分配给他们

Akka.NET有一个适用于此类场景的工具。我已经用一些额外的日志记录和路由器配置更新了您的示例代码

void Main()
{
    ContainerBuilder builder = new ContainerBuilder();
    builder.RegisterType<Worker>();
    builder.RegisterType<WorkerManager>();
    var container = builder.Build();

    var system = ActorSystem.Create("DITestSystem");
    var resolver = new AutoFacDependencyResolver(container, system);

    var manager = system.ActorOf(system.DI().Props<WorkerManager>(), "Manager");
    Console.WriteLine("Program: Created Manager");

    for (int i = 0; i < 10; i++)
    {
        manager.Tell("Hello");
    }

    Console.ReadKey(true);
}

public class Worker : ReceiveActor
{
    public Worker()
    {
        Receive<string>(m => Console.WriteLine($"Worker {Context.Self.Path.Name} received: {m}"));
    }

    protected override void PreStart()
    {
        Console.WriteLine($"PreStart: {Context.Self.Path}");
    }
}

public class WorkerManager : ReceiveActor
{
    IActorRef worker;

    public WorkerManager()
    {
        Receive<string>(m =>
        {
            Console.WriteLine($"Manager received: {m}");
            worker.Tell(m);
        });
    }

    protected override void PreStart()
    {
        Console.WriteLine($"PreStart: {Context.Self.Path}");

        var props = Context.DI().Props<Worker>().WithRouter(new RoundRobinPool(5));
        worker = Context.ActorOf(props, "Worker");
    }
}
这将导致
ManagerActor
以循环方式将消息转发给5个子
Worker
参与者。消息路由由您负责,因此无需直接与
工作者
参与者交互

var props = Context.DI().Props<Worker>().WithRouter(new RoundRobinPool(5));
现在,该示例在获得对它的引用后,还会立即向
ManagerActor
发送10条消息

for (int i = 0; i < 10; i++)
{
    manageRef.Tell("Hello");
}
这是另一个的输出

Program: Created Manager
PreStart: akka://DITestSystem/user/Manager
PreStart: akka://DITestSystem/user/Manager/Worker/$b
PreStart: akka://DITestSystem/user/Manager/Worker/$c
PreStart: akka://DITestSystem/user/Manager/Worker/$d
PreStart: akka://DITestSystem/user/Manager/Worker/$f
PreStart: akka://DITestSystem/user/Manager/Worker/$e
Manager received: Hello
Manager received: Hello
Manager received: Hello
Manager received: Hello
Worker $d received: Hello
Worker $e received: Hello
Manager received: Hello
Manager received: Hello
Manager received: Hello
Manager received: Hello
Manager received: Hello
Worker $f received: Hello
Worker $e received: Hello
Manager received: Hello
Worker $f received: Hello
Worker $b received: Hello
Worker $b received: Hello
Worker $c received: Hello
Worker $c received: Hello
Worker $d received: Hello
您可以看到,在第一次运行中,
WorkerManager
在创建任何子
Worker
参与者之前已收到所有消息。在第二次运行中,它在接收任何消息之前创建了所有子
工作者
参与者


要记住的要点是,最好与消息沟通,不要对事情发生的时间做出假设。

这里的问题是竞争条件。无论是否使用DI容器创建参与者,都可能发生这种情况

当使用actor系统时,您需要记住所有事情都是异步发生的。您可以在将消息发送到
WorkerManager
参与者后继续编写代码,但这并不意味着消息实际上已被接收和处理。它实际上被发布到一个邮箱,以便参与者在准备就绪时在另一个线程上处理

如果您有一个
WorkerManager
actor,最好不要尝试直接访问
Worker
actor。就像在现实生活中一样,你通常会要求经理组织一些要做的工作,然后经理会反过来决定哪些员工是工人