Skip to content

Commit

Permalink
make AkkaHostedService public + virtual (#306)
Browse files Browse the repository at this point in the history
* make AkkaHostedService `public` + `virtual`

Re-implementation of #299

Made clear in XML-DOC comment, this is a "there be dragons" use case for end-users. We're not going to provide you with much support beyond making this possible. Best of luck.

* implemented fixes
  • Loading branch information
Aaronontheweb authored May 17, 2023
1 parent 92708e7 commit 3dcde9d
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,25 @@ namespace Akka.Hosting
where T : Akka.Actor.IExtensionId { }
public Akka.Hosting.AkkaConfigurationBuilder WithExtensions(params System.Type[] extensions) { }
}
[Akka.Annotations.InternalApi]
public class AkkaHostedService : Microsoft.Extensions.Hosting.IHostedService
{
protected Akka.Actor.ActorSystem? ActorSystem;
protected readonly Akka.Hosting.AkkaConfigurationBuilder ConfigurationBuilder;
protected Akka.Actor.CoordinatedShutdown? CoordinatedShutdown;
protected readonly Microsoft.Extensions.Hosting.IHostApplicationLifetime? HostApplicationLifetime;
protected readonly Microsoft.Extensions.Logging.ILogger<Akka.Hosting.AkkaHostedService> Logger;
protected readonly System.IServiceProvider ServiceProvider;
public AkkaHostedService(Akka.Hosting.AkkaConfigurationBuilder configurationBuilder, System.IServiceProvider serviceProvider, Microsoft.Extensions.Logging.ILogger<Akka.Hosting.AkkaHostedService> logger, Microsoft.Extensions.Hosting.IHostApplicationLifetime? applicationLifetime) { }
public virtual System.Threading.Tasks.Task StartAsync(System.Threading.CancellationToken cancellationToken) { }
public virtual System.Threading.Tasks.Task StopAsync(System.Threading.CancellationToken cancellationToken) { }
}
public static class AkkaHostingExtensions
{
public static Microsoft.Extensions.DependencyInjection.IServiceCollection AddAkka(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, string actorSystemName, System.Action<Akka.Hosting.AkkaConfigurationBuilder> builder) { }
public static Microsoft.Extensions.DependencyInjection.IServiceCollection AddAkka(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, string actorSystemName, System.Action<Akka.Hosting.AkkaConfigurationBuilder, System.IServiceProvider> builder) { }
public static Microsoft.Extensions.DependencyInjection.IServiceCollection AddAkka<T>(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, string actorSystemName, System.Action<Akka.Hosting.AkkaConfigurationBuilder, System.IServiceProvider> builder)
where T : Akka.Hosting.AkkaHostedService { }
public static Akka.Hosting.AkkaConfigurationBuilder AddHocon(this Akka.Hosting.AkkaConfigurationBuilder builder, Akka.Configuration.Config hocon, Akka.Hosting.HoconAddMode addMode) { }
public static Akka.Hosting.AkkaConfigurationBuilder AddHocon(this Akka.Hosting.AkkaConfigurationBuilder builder, Microsoft.Extensions.Configuration.IConfiguration configuration, Akka.Hosting.HoconAddMode addMode) { }
public static Akka.Hosting.AkkaConfigurationBuilder AddHoconFile(this Akka.Hosting.AkkaConfigurationBuilder builder, string hoconFilePath, Akka.Hosting.HoconAddMode addMode) { }
Expand Down
53 changes: 30 additions & 23 deletions src/Akka.Hosting/AkkaHostedService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Threading;
using System.Threading.Tasks;
using Akka.Actor;
using Akka.Annotations;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
Expand All @@ -11,36 +12,42 @@ namespace Akka.Hosting
/// <summary>
/// INTERNAL API
/// </summary>
internal sealed class AkkaHostedService : IHostedService
/// <remarks>
/// Open for modification in cases where users need fine-grained control over <see cref="Actor.ActorSystem"/> startup and
/// DI - however, extend at your own risk. Look at the Akka.Hosting source code for ideas on how to extend this.
/// </remarks>
[InternalApi]
// ReSharper disable once ClassWithVirtualMembersNeverInherited.Global
public class AkkaHostedService : IHostedService
{
private ActorSystem? _actorSystem;
private CoordinatedShutdown? _coordinatedShutdown; // grab a reference to CoordinatedShutdown early
private readonly IServiceProvider _serviceProvider;
private readonly AkkaConfigurationBuilder _configurationBuilder;
private readonly IHostApplicationLifetime? _hostApplicationLifetime;
private readonly ILogger<AkkaHostedService> _logger;
protected ActorSystem? ActorSystem;
protected CoordinatedShutdown? CoordinatedShutdown; // grab a reference to CoordinatedShutdown early
protected readonly IServiceProvider ServiceProvider;
protected readonly AkkaConfigurationBuilder ConfigurationBuilder;
protected readonly IHostApplicationLifetime? HostApplicationLifetime;
protected readonly ILogger<AkkaHostedService> Logger;

public AkkaHostedService(AkkaConfigurationBuilder configurationBuilder, IServiceProvider serviceProvider,
ILogger<AkkaHostedService> logger, IHostApplicationLifetime? applicationLifetime)
{
_configurationBuilder = configurationBuilder;
_hostApplicationLifetime = applicationLifetime;
_serviceProvider = serviceProvider;
_logger = logger;
ConfigurationBuilder = configurationBuilder;
HostApplicationLifetime = applicationLifetime;
ServiceProvider = serviceProvider;
Logger = logger;
}

public async Task StartAsync(CancellationToken cancellationToken)
public virtual async Task StartAsync(CancellationToken cancellationToken)
{
try
{
_actorSystem = _serviceProvider.GetRequiredService<ActorSystem>();
_coordinatedShutdown = CoordinatedShutdown.Get(_actorSystem);
await _configurationBuilder.StartAsync(_actorSystem);
ActorSystem = ServiceProvider.GetRequiredService<ActorSystem>();
CoordinatedShutdown = CoordinatedShutdown.Get(ActorSystem);
await ConfigurationBuilder.StartAsync(ActorSystem);

async Task TerminationHook()
{
await _actorSystem.WhenTerminated.ConfigureAwait(false);
_hostApplicationLifetime?.StopApplication();
await ActorSystem.WhenTerminated.ConfigureAwait(false);
HostApplicationLifetime?.StopApplication();
}

// terminate the application if the Sys is terminated first
Expand All @@ -51,22 +58,22 @@ async Task TerminationHook()
}
catch (Exception ex)
{
_logger.Log(LogLevel.Critical, ex, "Unable to start AkkaHostedService - shutting down application");
_hostApplicationLifetime?.StopApplication();
Logger.Log(LogLevel.Critical, ex, "Unable to start AkkaHostedService - shutting down application");
HostApplicationLifetime?.StopApplication();
}
}

public async Task StopAsync(CancellationToken cancellationToken)
public virtual async Task StopAsync(CancellationToken cancellationToken)
{
// ActorSystem may have failed to start - skip shutdown sequence if that's the case
// so error message doesn't get conflated.
if (_coordinatedShutdown == null)
if (CoordinatedShutdown == null)
{
return;
}

// run full CoordinatedShutdown on the Sys
await _coordinatedShutdown.Run(CoordinatedShutdown.ClrExitReason.Instance)
await CoordinatedShutdown.Run(CoordinatedShutdown.ClrExitReason.Instance)
.ConfigureAwait(false);
}
}
Expand Down
7 changes: 6 additions & 1 deletion src/Akka.Hosting/AkkaHostingExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ public static IServiceCollection AddAkka(this IServiceCollection services, strin
/// and manages its lifecycle in accordance with Akka.NET best practices.
/// </remarks>
public static IServiceCollection AddAkka(this IServiceCollection services, string actorSystemName, Action<AkkaConfigurationBuilder, IServiceProvider> builder)
{
return AddAkka<AkkaHostedService>(services, actorSystemName, builder);
}

public static IServiceCollection AddAkka<T>(this IServiceCollection services, string actorSystemName, Action<AkkaConfigurationBuilder, IServiceProvider> builder) where T:AkkaHostedService
{
var b = new AkkaConfigurationBuilder(services, actorSystemName);
services.AddSingleton<AkkaConfigurationBuilder>(sp =>
Expand All @@ -72,7 +77,7 @@ public static IServiceCollection AddAkka(this IServiceCollection services, strin
else
{
// start the IHostedService which will run Akka.NET
services.AddHostedService<AkkaHostedService>();
services.AddHostedService<T>();
}

return services;
Expand Down

0 comments on commit 3dcde9d

Please sign in to comment.