☰
Akka.NET 部署到 Azure Cloud Service:Worker Role 宿主模式与 ActorSystem 生命周期管理
2026/10/14 15:25:10 网站建设 项目流程
  • 后端
  • 微服务

【免费下载链接】akka.net

Canonical actor model implementation for .NET with local + distributed actors in C# and F#.

项目地址:https://gitcode.com/gh_mirrors/ak/akka.net
点击查看免费下载

本文讲解如何将 Akka.NET 的ActorSystem托管到 Azure PaaS Cloud Service 的 Worker Role 中,涵盖RoleEntryPoint的OnStart/Run/OnStop生命周期与 Actor 系统的启动、阻塞等待、优雅关闭的完整实现,并结合当前仓库中的 Windows Service / Headless Service 示例源码,说明该部署模式与现代BackgroundService宿主模式的对应关系,帮助你在遗留 Azure 项目中正确移植或维护 Akka.NET 宿主代码。

背景:Azure Cloud Service(已弃用)与 Worker Role

首先需要明确一个前提:Azure Cloud Service 如今已大面积弃用(largely deprecated in Azure)。官方文档在文首即以醒目提示标注了这一点。因此本文的定位是:如果你需要阅读、维护或移植基于旧版 Azure PaaS Cloud Service 模板的 Akka.NET 宿主代码(这也是当前文档的原始场景),应当如何理解其结构与生命周期;如果你是在新建项目,则应优先参考后文给出的现代BackgroundService替代方案。

原文档描述的部署模型是:

  • 在 Visual Studio 中安装 Azure .NET SDK 后,可使用其提供的项目模板创建一个包含单个空 Worker Role的 Azure PaaS Cloud Service 工程;
  • Worker Role 的宿主代码结构与 Windows Service 非常相似——本质上都是"进程宿主 + 顶层用户 Actor"的长驻服务模式;
  • 部署到云端之前,可以使用Azure Compute Emulator在本地对 Worker Role 实现进行测试与调试。

快速上手方式是:创建一个简单的 Worker Role,在其RunAsync()方法中启动顶层用户 Actor。下面给出完整实现。

WorkerRole.cs 完整实现

using Akka.Actor; namespace MyActorWorkerRole { public class WorkerRole : RoleEntryPoint { private readonly CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(); private readonly ManualResetEvent runCompleteEvent = new ManualResetEvent(false); private ActorSystem _actorSystem; public override bool OnStart() { // Setup the Actor System _actorSystem = ActorSystem.Create("MySystem"); return (base.OnStart()); } public override void OnStop() { this.cancellationTokenSource.Cancel(); this.runCompleteEvent.WaitOne(); // Shutdown the Actor System _actorSystem.Shutdown(); base.OnStop(); } public override void Run() { try { this.RunAsync(this.cancellationTokenSource.Token).Wait(); } finally { this.runCompleteEvent.Set(); } } private async Task RunAsync(CancellationToken cancellationToken) { // Create an instance to the top-level user Actor var workerRoleActor = _actorSystem.ActorOf<WorkerRoleActor>("WorkerRole"); // Send a message to the Actor workerRoleActor.Tell(new WorkerRoleMessage("Hello World!")); while (!cancellationToken.IsCancellationRequested) { await Task.Delay(1000, cancellationToken); } } } }

逐段解读:Azure 宿主与 Akka 生命周期的衔接

这段代码虽然简短,但每个成员都承担了明确的职责,值得逐段拆解:

  1. OnStart()—— 创建 ActorSystemAzure SDK 的RoleEntryPoint基类在实例化 Worker Role 后调用OnStart()。这里创建名为"MySystem"的ActorSystem(对应源码中ActorSystem.Create工厂方法,参见 ActorSystem),然后调用base.OnStart()让 Azure 运行时完成自身初始化。注意OnStart()返回false会导致角色实例启动失败,所以务必保持return base.OnStart()。

  2. Run()—— 阻塞宿主线程直到取消Azure 要求Run()保持阻塞以维持 Worker Role 存活。实现上用RunAsync(...).Wait()同步等待异步主循环;finally中runCompleteEvent.Set()释放一个ManualResetEvent,供OnStop()感知"Run 已完成",从而保证关闭时序。

  3. RunAsync()—— 启动顶层 Actor 并保活

    • _actorSystem.ActorOf<WorkerRoleActor>("WorkerRole")派生出顶层用户 ActorWorkerRole(路径为akka://MySystem/user/WorkerRole);
    • 通过Tell(new WorkerRoleMessage("Hello World!"))向其发送第一条消息;
    • 随后进入while (!cancellationToken.IsCancellationRequested)保活循环,Task.Delay(1000, cancellationToken)让线程在等待中让出,且取消令牌触发时循环可立即退出——这是整个"进程保活"的关键。
  4. OnStop()—— 按序优雅关闭关闭顺序是这段代码最重要的语义,共三步:

    • cancellationTokenSource.Cancel():通知RunAsync主循环退出;
    • runCompleteEvent.WaitOne():阻塞等待Run()的finally分支执行完毕,确认主循环已停止;
    • _actorSystem.Shutdown():关闭 Actor 系统。

    从源码结构看,ActorSystem的Shutdown与Terminate语义不同:Shutdown在系统终止前会先运行 CoordinatedShutdown 的协调关闭流程(若已启用),再逐步停止 Actor;对仅含少量无状态 Actor 的 Worker Role 而言,直接Shutdown()已足够。仓库中更完善的 Headless Service 示例则展示了关闭时的推荐写法——显式触发协调关闭:

    // src/examples/HeadlessService/AkkaHeadlesssService/AkkaService.cs await CoordinatedShutdown.Get(_actorSystem).Run(CoordinatedShutdown.ClrExitReason.Instance);

    如果你移植该 Worker Role 且启用了 Cluster/持久化等模块,建议照此处理,可保证集群成员、消息等在 CLR 退出前被妥善处理。

本地调试:Azure Compute Emulator

在部署到 Azure 之前,原文档指出 Worker Role 实现可以先用 Azure Compute Emulator 在本地验证:它在本地模拟 Cloud Service 的启动、停止等生命周期事件,因此可以完整走到OnStart→Run→OnStop三条路径,等价于验证上面整个生命周期代码。调试要点:

  • 关注OnStart()是否返回true——这是角色启动成功的唯一信号;
  • 关注OnStop()中"取消 → 等待 → 关闭"的时序是否都实际执行(可通过 ActorSystem 的终止日志确认Shutdown()被调用)。

现代替代:BackgroundService / IHostedService 宿主模式

由于 Cloud Service 已弃用,新建项目不应再使用RoleEntryPoint,而是采用Microsoft.Extensions.Hosting的BackgroundService(IHostedService)模式——这正是原文档所说的"与 Windows Service 实现非常相似"的当代形态。当前仓库提供了两套可直接对照的示例。

示例一:Windows Service(BackgroundService + DI)

位于 src/examples/WindowsService/AkkaWindowsService:

Program.cs通过Host.CreateDefaultBuilder+UseWindowsService注册宿主:

using IHost host = Host.CreateDefaultBuilder(args) .UseWindowsService(options => { options.ServiceName = ".NET Joke Service"; }) .ConfigureServices(services => { services.AddHostedService<AkkaService>(); services.AddHttpClient<JokeService>(); }) .Build(); await host.RunAsync();

AkkaService(BackgroundService子类)把 Worker Role 示例中的职责一一映射到了新的宿主模型上:

public sealed class AkkaService : BackgroundService { private readonly ILogger<AkkaService> _logger; private readonly JokeService _jokeService; private readonly ActorSystem _actorSystem; private readonly IActorRef _actorRef; public AkkaService(JokeService jokeService, ILogger<AkkaService> logger, IServiceProvider serviceProvider) { _jokeService = jokeService; _logger = logger; var bootstrap = BootstrapSetup.Create(); // enable DI support inside this ActorSystem, if needed var diSetup = DependencyResolverSetup.Create(serviceProvider); // merge this setup (and any others) together into ActorSystemSetup var actorSystemSetup = bootstrap.And(diSetup); // start ActorSystem _actorSystem = ActorSystem.Create("akka-system", actorSystemSetup); _actorRef = _actorSystem.ActorOf(MyActor.Prop()); } protected override async Task ExecuteAsync(CancellationToken stoppingToken) { while (!stoppingToken.IsCancellationRequested) { var joke = await _jokeService.GetJokeAsync(); _logger.LogWarning(joke); await Task.Delay(TimeSpan.FromMinutes(1), stoppingToken); _actorRef.Tell(joke); } } }

对照关系非常清晰:

Worker Role(RoleEntryPoint)BackgroundService(现代宿主)
OnStart()中ActorSystem.Create构造函数中创建ActorSystem,并可叠加DependencyResolverSetup启用 Actor 内 DI(来自 Akka.DependencyInjection)
RunAsync()的保活循环ExecuteAsync(stoppingToken)的主循环
CancellationTokenSource.Cancel()宿主框架下发的stoppingToken
OnStop()中_actorSystem.Shutdown()由IHostedService.StopAsync或CoordinatedShutdown处理

该示例的工程文件 AkkaWindowsService.csproj 显示其依赖Microsoft.Extensions.Hosting.WindowsServices(注册为 Windows 服务)与Microsoft.Extensions.Http(JokeService使用的 HTTP 客户端),并通过ProjectReference引用core/Akka与contrib/dependencyinjection/Akka.DependencyInjection。

示例二:Headless Service(IHostedService + 协调关闭)

位于 src/examples/HeadlessService/AkkaHeadlesssService,展示了与 Azure Worker Role 场景最贴近的"无界面后台服务"写法:

public Task StartAsync(CancellationToken cancellationToken) { var bootstrap = BootstrapSetup.Create(); var diSetup = DependencyResolverSetup.Create(_serviceProvider); var actorSystemSetup = bootstrap.And(diSetup); // start ActorSystem _actorSystem = ActorSystem.Create("headless-service", actorSystemSetup); _actorRef = _actorSystem.ActorOf(HeadlessActor.Prop()); // add a continuation task that will guarantee shutdown of application if ActorSystem terminates _actorSystem.WhenTerminated.ContinueWith(_ => { _applicationLifetime.StopApplication(); }); return Task.CompletedTask; } public async Task StopAsync(CancellationToken cancellationToken) { // strictly speaking this may not be necessary - terminating the ActorSystem would also work // but this call guarantees that the shutdown of the cluster is graceful regardless await CoordinatedShutdown.Get(_actorSystem).Run(CoordinatedShutdown.ClrExitReason.Instance); }

相比 Worker Role 示例,它多了两个值得移植时吸收的细节:

  1. _actorSystem.WhenTerminated.ContinueWith(...)调用_applicationLifetime.StopApplication():一旦 ActorSystem 因任何原因终止(如 Actor 抛出未捕获错误导致系统关闭),宿主进程随之停止,避免"进程活着但 Actor 已死"的僵尸状态;
  2. StopAsync中显式CoordinatedShutdown.Get(...).Run(CoordinatedShutdown.ClrExitReason.Instance):如源码注释所述,"严格来说终止 ActorSystem 也可以,但该调用可保证关闭(含集群场景)是优雅的"。

小结

  • Azure Cloud Service 的 Worker Role 宿主模式 =OnStart建系统、Run保活、OnStop取消-等待-关闭;完整参考实现见 docs/articles/deployment/azure-cloud-service.md;
  • 该文档已标注 Cloud Service 大面积弃用,新建宿主请直接使用BackgroundService/IHostedService,参考仓库示例 src/examples/WindowsService 与 src/examples/HeadlessService,部署场景总览见 docs/articles/deployment/index.md;
  • 无论哪种宿主,关闭路径的核心都不变:先停主循环,再关闭ActorSystem,涉及集群/持久化时优先走CoordinatedShutdown。
  • 后端
  • 微服务

【免费下载链接】akka.net

Canonical actor model implementation for .NET with local + distributed actors in C# and F#.

项目地址:https://gitcode.com/gh_mirrors/ak/akka.net
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询