我正在开发一个小的演员系统,当演员层次 struct 中出现问题时,我希望关闭所有演员并重新启动顶级演员,这样一切都从一个干净的状态开始.

我可以很容易地做到这一点,在中间参与者中实现监督策略来升级错误,然后让顶级参与者重新启动.然而,正如this video中所描述的,重新启动并不清除actors邮箱,我想这样做是为了真正确保一切都重新开始.

到目前为止,我还没有找到任何关于如何清理邮箱的文档,所以我甚至不确定这是否可能.

然而,由于我不想只是重新启动,而是有一些延迟,我查看了BackoffSupervisor.据我所知,当一个演员被BackoffSupervisor分重启时,它实际上并没有重新启动,而是在退避期间停止,然后重新启动,这意味着它的邮箱实际上是被清除的,正如我所希望的那样.这个解决方案对我有效,但我想确保这个行为是故意这样的,并且我可以在这个用例中依赖它.

可能不太相关,但作为参考,以防万一,我就是这样创建这个主管的:

return BackoffSupervisor.Props(
    Backoff.OnFailure(
        rootActorProps,
        childName: nameof(RootActor),
        minBackoff: TimeSpan.FromSeconds(1),
        maxBackoff: TimeSpan.FromMinutes(5),
        randomFactor: 0.2,
        -1));

所以,概括地说,我的疑问是:

  • 有没有可能以某种方式清理演员的邮箱?
  • 使用BackoffSupervisor是获取邮箱的有效方法,其他一切都以干净的状态重新启动

推荐答案

这是我写的LINQPad脚本-请忽略ActorSytem个终止内容;我只是需要它来确保程序停止运行;)

async Task Main()
{
    // Initialize Actor System
    var system = ActorSystem.Create("MySystem");

    // Create Props for the EchoActor
    var props = Props.Create<EchoActor>();

    // Create the EchoActor
    var echoActor = system.ActorOf(props, "echoActor");

    // Send 10 messages to the EchoActor
    for (int i = 0; i < 10; i++)
    {
        echoActor.Tell($"Message {i + 1}");
    }

    // Allow some time for messages to process before shutting down
    await system.WhenTerminated;
}

// Define the EchoActor class
public class EchoActor : ReceiveActor
{
    public EchoActor()
    {
        NormalBehavior();       
    }

    private void NormalBehavior()
    {
        ReceiveAnyAsync(async message =>
        {
            await Task.Delay(100);
            Console.WriteLine($"Received and echoing back: {message}");
            throw new ApplicationException("restart");
        });
    }
    
    private void RecoverBehavior(){
        Receive<RecoverMarker>(_ =>{
            Become(NormalBehavior);
            Context.System.Terminate();
        });
        
        ReceiveAny(_ =>{
            // discard
            Console.WriteLine($"Discarding: {_}");
        });
    }

    private class RecoverMarker{}
    
    protected override void PreRestart(Exception ex, object message){
        Self.Tell(new RecoverMarker());
    }
    
    protected override void PostRestart(Exception ex){
        Become(RecoverBehavior);
    }
}

该示例的工作原理:它使用behavior switching在参与者重新启动后立即将其移动到"丢弃"模式,并且当参与者的旧实例被销毁时,"重新启动标记"被推入参与者的邮箱.演员将丢弃所有较旧的消息,直到它达到RestartMarker.

这是解决此问题的通用方法,它无需触及内部邮箱API等即可工作.

Csharp相关问答推荐

CsWin32如何创建PWSTR的实例,例如GetWindowText

如何使用CsvReader获取给定列索引的列标题?

Microsoft. VisualBasic. FileIO. FileSystem. MoveFile()对话框有错误?

在C#WinUI中,一个关于System的崩溃."由于未知原因导致执行不例外"

最新的Mediatr和具有同步方法的处理程序Handle:并非所有代码路径都返回值"

从ASP.NET Core中的枚举字段填充 Select 选项时,将默认的第一个选项添加为 Select 元素

如何在ASP.NET Core8中启用REST应用程序的序列化?

等待一个等待函数

同一组件的多个实例触发相同的事件处理程序

为什么我不能从我的异步任务方法中返回异步任务方法?

我找不到ASP.NET Web应用程序(.NET框架).已 Select .NET框架项目和项模板以及此组件(&Q;)

.NET8Blazor-为什么Rapzor渲染在for循环之后显示?

Xamarin.Forms-如何创建可 Select 的显示alert 或弹出窗口?

在ObservableCollection上使用[NotifyPropertyChangedFor()]源代码生成器不会更新UI

为什么我的属性即使没有显式地设置任何[必需]属性,也会显示验证?

SignalR跨域

使用SQL Server 2022+时,我是否必须将代码从SqlConnection类对象中迁移出来?

有没有更好的方法来使用LINQ获取整行的计算组

反编译源代码时出现奇怪的字符

如何在C#中用Serilog记录类路径、方法名和行编号