Skip to content

Commit 4724638

Browse files
Make AkkaHostedService public (#299)
Co-authored-by: Aaron Stannard <aaron@petabridge.com>
1 parent bd2449d commit 4724638

File tree

3 files changed

+106
-37
lines changed

3 files changed

+106
-37
lines changed

src/Akka.Hosting.API.Tests/verify/CoreApiSpec.ApproveCore.verified.txt

+16
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,26 @@ namespace Akka.Hosting
4545
where T : Akka.Actor.IExtensionId { }
4646
public Akka.Hosting.AkkaConfigurationBuilder WithExtensions(params System.Type[] extensions) { }
4747
}
48+
public abstract class AkkaHostedService : Microsoft.Extensions.Hosting.IHostedService
49+
{
50+
protected AkkaHostedService(Akka.Hosting.AkkaConfigurationBuilder configurationBuilder, System.IServiceProvider serviceProvider, Microsoft.Extensions.Logging.ILogger<Akka.Hosting.AkkaHostedService> logger, Microsoft.Extensions.Hosting.IHostApplicationLifetime applicationLifetime) { }
51+
protected Akka.Actor.ActorSystem ActorSystem { get; }
52+
protected Akka.Actor.CoordinatedShutdown CoordinatedShutdown { get; }
53+
protected Microsoft.Extensions.Hosting.IHostApplicationLifetime HostApplicationLifetime { get; }
54+
protected bool Initialized { get; }
55+
protected Microsoft.Extensions.Logging.ILogger<Akka.Hosting.AkkaHostedService> Logger { get; }
56+
protected System.IServiceProvider ServiceProvider { get; }
57+
protected System.Threading.Tasks.Task StartAkkaAsync(System.Threading.CancellationToken cancellationToken) { }
58+
public virtual System.Threading.Tasks.Task StartAsync(System.Threading.CancellationToken cancellationToken) { }
59+
protected System.Threading.Tasks.Task StopAkkaAsync(System.Threading.CancellationToken cancellationToken) { }
60+
public virtual System.Threading.Tasks.Task StopAsync(System.Threading.CancellationToken cancellationToken) { }
61+
}
4862
public static class AkkaHostingExtensions
4963
{
5064
public static Microsoft.Extensions.DependencyInjection.IServiceCollection AddAkka(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, string actorSystemName, System.Action<Akka.Hosting.AkkaConfigurationBuilder> builder) { }
5165
public static Microsoft.Extensions.DependencyInjection.IServiceCollection AddAkka(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, string actorSystemName, System.Action<Akka.Hosting.AkkaConfigurationBuilder, System.IServiceProvider> builder) { }
66+
public static Microsoft.Extensions.DependencyInjection.IServiceCollection AddAkka<T>(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, string actorSystemName, System.Action<Akka.Hosting.AkkaConfigurationBuilder, System.IServiceProvider> builder)
67+
where T : Akka.Hosting.AkkaHostedService { }
5268
public static Akka.Hosting.AkkaConfigurationBuilder AddHocon(this Akka.Hosting.AkkaConfigurationBuilder builder, Akka.Configuration.Config hocon, Akka.Hosting.HoconAddMode addMode) { }
5369
public static Akka.Hosting.AkkaConfigurationBuilder AddHocon(this Akka.Hosting.AkkaConfigurationBuilder builder, Microsoft.Extensions.Configuration.IConfiguration configuration, Akka.Hosting.HoconAddMode addMode) { }
5470
public static Akka.Hosting.AkkaConfigurationBuilder AddHoconFile(this Akka.Hosting.AkkaConfigurationBuilder builder, string hoconFilePath, Akka.Hosting.HoconAddMode addMode) { }

src/Akka.Hosting/AkkaHostedService.cs

+78-35
Original file line numberDiff line numberDiff line change
@@ -8,66 +8,109 @@
88

99
namespace Akka.Hosting
1010
{
11-
/// <summary>
12-
/// INTERNAL API
13-
/// </summary>
14-
internal sealed class AkkaHostedService : IHostedService
11+
public abstract class AkkaHostedService : IHostedService
1512
{
1613
private ActorSystem? _actorSystem;
1714
private CoordinatedShutdown? _coordinatedShutdown; // grab a reference to CoordinatedShutdown early
18-
private readonly IServiceProvider _serviceProvider;
15+
16+
protected IServiceProvider ServiceProvider { get; }
17+
protected IHostApplicationLifetime HostApplicationLifetime { get; }
18+
protected ILogger<AkkaHostedService> Logger { get; }
19+
1920
private readonly AkkaConfigurationBuilder _configurationBuilder;
20-
private readonly IHostApplicationLifetime _hostApplicationLifetime;
21-
private readonly ILogger<AkkaHostedService> _logger;
2221

23-
public AkkaHostedService(AkkaConfigurationBuilder configurationBuilder, IServiceProvider serviceProvider,
22+
protected AkkaHostedService(AkkaConfigurationBuilder configurationBuilder, IServiceProvider serviceProvider,
2423
ILogger<AkkaHostedService> logger, IHostApplicationLifetime applicationLifetime)
2524
{
2625
_configurationBuilder = configurationBuilder;
27-
_hostApplicationLifetime = applicationLifetime;
28-
_serviceProvider = serviceProvider;
29-
_logger = logger;
26+
HostApplicationLifetime = applicationLifetime;
27+
ServiceProvider = serviceProvider;
28+
Logger = logger;
29+
}
30+
31+
protected ActorSystem ActorSystem
32+
{
33+
get
34+
{
35+
if (_actorSystem is null)
36+
throw new Exception("ActorSystem has not been initialized");
37+
return _actorSystem;
38+
}
3039
}
3140

32-
public async Task StartAsync(CancellationToken cancellationToken)
41+
protected CoordinatedShutdown CoordinatedShutdown
3342
{
34-
try
43+
get
3544
{
36-
_actorSystem = _serviceProvider.GetRequiredService<ActorSystem>();
37-
_coordinatedShutdown = CoordinatedShutdown.Get(_actorSystem);
38-
await _configurationBuilder.StartAsync(_actorSystem);
45+
if (_coordinatedShutdown is null)
46+
throw new Exception("ActorSystem has not been initialized");
47+
return _coordinatedShutdown;
48+
}
49+
}
3950

40-
async Task TerminationHook()
41-
{
42-
await _actorSystem.WhenTerminated.ConfigureAwait(false);
43-
_hostApplicationLifetime.StopApplication();
44-
}
51+
protected bool Initialized => _coordinatedShutdown is not null;
4552

46-
// terminate the application if the Sys is terminated first
47-
// this can happen in instances such as Akka.Cluster membership changes
48-
#pragma warning disable CS4014
49-
TerminationHook();
50-
#pragma warning restore CS4014
51-
}
52-
catch (Exception ex)
53+
protected async Task StartAkkaAsync(CancellationToken cancellationToken)
54+
{
55+
_actorSystem = ServiceProvider.GetRequiredService<ActorSystem>();
56+
_coordinatedShutdown = CoordinatedShutdown.Get(_actorSystem);
57+
await _configurationBuilder.StartAsync(_actorSystem);
58+
59+
async Task TerminationHook()
5360
{
54-
_logger.Log(LogLevel.Critical, ex, "Unable to start AkkaHostedService - shutting down application");
55-
_hostApplicationLifetime.StopApplication();
61+
await _actorSystem.WhenTerminated.ConfigureAwait(false);
62+
HostApplicationLifetime.StopApplication();
5663
}
64+
65+
// terminate the application if the Sys is terminated first
66+
// this can happen in instances such as Akka.Cluster membership changes
67+
#pragma warning disable CS4014
68+
TerminationHook();
69+
#pragma warning restore CS4014
5770
}
5871

59-
public async Task StopAsync(CancellationToken cancellationToken)
72+
protected async Task StopAkkaAsync(CancellationToken cancellationToken)
6073
{
6174
// ActorSystem may have failed to start - skip shutdown sequence if that's the case
6275
// so error message doesn't get conflated.
63-
if (_coordinatedShutdown == null)
64-
{
76+
if (!Initialized)
6577
return;
66-
}
6778

6879
// run full CoordinatedShutdown on the Sys
69-
await _coordinatedShutdown.Run(CoordinatedShutdown.ClrExitReason.Instance)
80+
await CoordinatedShutdown.Run(CoordinatedShutdown.ClrExitReason.Instance)
7081
.ConfigureAwait(false);
7182
}
83+
84+
public virtual async Task StartAsync(CancellationToken cancellationToken)
85+
{
86+
try
87+
{
88+
await StartAkkaAsync(cancellationToken);
89+
}
90+
catch (Exception ex)
91+
{
92+
Logger.Log(LogLevel.Critical, ex, "Unable to start AkkaHostedService - shutting down application");
93+
HostApplicationLifetime.StopApplication();
94+
}
95+
}
96+
97+
public virtual async Task StopAsync(CancellationToken cancellationToken)
98+
{
99+
await StopAkkaAsync(cancellationToken);
100+
}
101+
}
102+
103+
/// <summary>
104+
/// INTERNAL API
105+
/// </summary>
106+
internal sealed class AkkaHostedServiceImpl : AkkaHostedService
107+
{
108+
public AkkaHostedServiceImpl(
109+
AkkaConfigurationBuilder configurationBuilder,
110+
IServiceProvider serviceProvider,
111+
ILogger<AkkaHostedService> logger,
112+
IHostApplicationLifetime applicationLifetime)
113+
: base(configurationBuilder, serviceProvider, logger, applicationLifetime)
114+
{ }
72115
}
73116
}

src/Akka.Hosting/AkkaHostingExtensions.cs

+12-2
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,17 @@ public static IServiceCollection AddAkka(this IServiceCollection services, strin
5151
/// Starts a background <see cref="IHostedService"/> that runs the <see cref="ActorSystem"/>
5252
/// and manages its lifecycle in accordance with Akka.NET best practices.
5353
/// </remarks>
54-
public static IServiceCollection AddAkka(this IServiceCollection services, string actorSystemName, Action<AkkaConfigurationBuilder, IServiceProvider> builder)
54+
public static IServiceCollection AddAkka(
55+
this IServiceCollection services,
56+
string actorSystemName,
57+
Action<AkkaConfigurationBuilder, IServiceProvider> builder)
58+
=> AddAkka<AkkaHostedServiceImpl>(services, actorSystemName, builder);
59+
60+
public static IServiceCollection AddAkka<T>(
61+
this IServiceCollection services,
62+
string actorSystemName,
63+
Action<AkkaConfigurationBuilder, IServiceProvider> builder)
64+
where T: AkkaHostedService
5565
{
5666
var b = new AkkaConfigurationBuilder(services, actorSystemName);
5767
services.AddSingleton<AkkaConfigurationBuilder>(sp =>
@@ -64,7 +74,7 @@ public static IServiceCollection AddAkka(this IServiceCollection services, strin
6474
b.Bind();
6575

6676
// start the IHostedService which will run Akka.NET
67-
services.AddHostedService<AkkaHostedService>();
77+
services.AddHostedService<T>();
6878

6979
return services;
7080
}

0 commit comments

Comments
 (0)