Coder Social home page Coder Social logo

akkadotnet / akka.hosting Goto Github PK

View Code? Open in Web Editor NEW
48.0 48.0 11.0 762 KB

Akka.Hosting - standardized Akka.NET hosting without any HOCON configuration. Ties into Microsoft.Extensions.Configuration, Logging, Hosting, and DependencyInjection.

License: Apache License 2.0

Batchfile 0.04% PowerShell 2.62% Shell 0.48% C# 96.83% Dockerfile 0.03% TSQL 0.01%
actor-model actors akkadotnet ihostedservice

akka.hosting's People

Contributors

aaronontheweb avatar arkatufus avatar cumpsd avatar dependabot[bot] avatar eaba avatar ingted avatar seanfarrow avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

akka.hosting's Issues

MAUI support for Akka.Hosting (disable `IHostedService`)

Is your feature request related to a problem? Please describe.

I spent some time chasing down a .NET MAUI user's issue getting IRequiredActor<TKey> to work correctly inside their application. Their ActorRegistry settings were correct and their code correctly binded Akka.NET to the MauiAppBuilder - the IHost equivalent for MAUI:

public static MauiAppBuilder Akka(this MauiAppBuilder builder)
{
    builder.Services.AddAkka("MyActorSystem", akkaConfigurationBuilder =>
    {
        akkaConfigurationBuilder.PipeActor();
    });

    return builder;
}

Yet the IRequiredActor<TKey> injection doesn't work and throws an actor resolution error upon trying, even with Akka.Hosting v1.5.4+ - why is that?

This is because MAUI doesn't support IHostedServices: dotnet/maui#2244

Describe the solution you'd like

Assuming that the rest of the core Akka DLL can even run on MAUI (i.e. there are no major AOT or other issues that would cause it to run not on the client), one solution we could try is configuring Akka.Hosting to run and launch all actors without the IHostedService. I think it might be possible to remove the IHostedService altogether without very little downside for regular users, possibly:

  • We can still shut the ActorSystem down using the IApplicationLifetime and continuation Tasks without needing the IHostedService.StopAsync method;
  • We already start the ActorSystem prior to the IHostedService.StartAsync method;
  • We already have a separate data structure for keeping track of what needs to be launched at startup - we could, in theory, just execute that as-is in the foreground with no code changes;
  • We already blow up the foreground process and kill it if there are problems starting any of the actors or Startup tasks - we'd just be doing that with one less layer of indirection under this arrangement.

To implement this, we'd need an integration test that demonstrates Akka.NET failing to boot up under MAUI now - and we'd need to get that test to turn green by removing the AkkaHostedService.

Describe alternatives you've considered

Alternatively, rather than removing the AkkaHostedService we could add an extension method that starts up Akka.NET without the IHostedService - or we could add an explicit MAUI build target and using compiler directives that avoid the use of the IHostedService in MAUI only. Those would lower the risk of Akka.Hosting having adverse side-effects for existing users.

Additional context
Add any other context or screenshots about the feature request here.

Finer grain control over ActorSystem startup

Is your feature request related to a problem? Please describe.

Right now, there is no proper programmatic way to defer/modify ActorSystem hosted service startup, everything is started immediately on host application start up.

Describe the solution you'd like

A way for users to modify/override the IHostedService.StartAsync() and IHostedService.StopAsync() methods.

Akka.Hosting.TestKit: `TestActor` is no longer the implicit sender

Version Information
Version of Akka.NET? 1.0.3
Which Akka.NET Modules? Akka.Hosting.TestKit

Describe the bug

 foreach (var i in Enumerable.Range(0, 2))
        {
            var update1 = Dsl.Update(CounterKey, GCounter.Empty, WriteLocal.Instance,
                g => g.Increment(selfAddress));
            replicator.Tell(update1);
            UpdateSuccess success1 = ExpectMsg<UpdateSuccess>();
        }

Fails and UpdateSuccess is a DeadLetter - this is because ActorRefs.NoSender is the sender.

Expected behavior

TestActor should be the implicit sender, just like in the normal testkit.

Actual behavior

There is no implicit sender.

Workaround

Can explicitly specify the TestActor as the sender.

 foreach (var i in Enumerable.Range(0, 2))
        {
            var update1 = Dsl.Update(CounterKey, GCounter.Empty, WriteLocal.Instance,
                g => g.Increment(selfAddress));
            replicator.Tell(update1, TestActor);
            UpdateSuccess success1 = ExpectMsg<UpdateSuccess>();
        }

Akka.Persistence.Hosting: add support for `IEventAdapters`

Is your feature request related to a problem? Please describe.

Based on a YouTube comment here: https://www.youtube.com/watch?v=Mnb9W9ClnB0&lc=UgwAV82O9_6CgesxVCl4AaABAg

This is really cool! Is there a plan to include event-bindings as being configurable? We have some persisted events that are now need to be upcasted, but I don't see a way to do that.

cc @briansain is that right? Doing this for the IEventAdapter in Akka.Persistence is what you meant?

Describe the solution you'd like
A clear and concise description of what you want to happen.

Describe alternatives you've considered
A clear and concise description of any alternative solutions or features you've considered.

Additional context
Add any other context or screenshots about the feature request here.

SimpleDemo Execution Exception

Version of Akka.NET? Which Akka.NET Modules? clone Akka.Hosting and executed Build.cmd

A clear and concise description of what the bug is.


[INFO][1/3/2023 5:31:47 AM][Thread 0001][remoting (akka://MyActorSystem)] Starting remoting
[INFO][1/3/2023 5:31:47 AM][Thread 0001][remoting (akka://MyActorSystem)] Remoting started; listening on addresses : [akka.tcp://MyActorSystem@localhost:8110]
[INFO][1/3/2023 5:31:47 AM][Thread 0001][remoting (akka://MyActorSystem)] Remoting now listens on addresses: [akka.tcp://MyActorSystem@localhost:8110]
[INFO][1/3/2023 5:31:47 AM][Thread 0001][Cluster (akka://MyActorSystem)] Cluster Node [akka.tcp://MyActorSystem@localhost:8110] - Starting up...
[INFO][1/3/2023 5:31:47 AM][Thread 0001][Cluster (akka://MyActorSystem)] Cluster Node [akka.tcp://MyActorSystem@localhost:8110] - Started up successfully
[INFO][1/3/2023 5:31:47 AM][Thread 0005][Cluster (akka://MyActorSystem)] Cluster Node [0.4.0] - Node [akka.tcp://MyActorSystem@localhost:8110] is JOINING itself (with roles [], version [0.4.0]) and forming a new cluster
[INFO][1/3/2023 5:31:47 AM][Thread 0005][Cluster (akka://MyActorSystem)] Cluster Node [akka.tcp://MyActorSystem@localhost:8110] - is the new leader among reachable nodes (more leaders may exist)
[INFO][1/3/2023 5:31:47 AM][Thread 0005][Cluster (akka://MyActorSystem)] Cluster Node [akka.tcp://MyActorSystem@localhost:8110] - Leader is moving node [akka.tcp://MyActorSystem@localhost:8110] to [Up]
[INFO][1/3/2023 5:31:47 AM][Thread 0015][akka.tcp://MyActorSystem@localhost:8110/system/sharding/myRegion] myRegion: Idle entities will be passivated after [00:02:00]
[INFO][1/3/2023 5:31:48 AM][Thread 0013][akka.tcp://MyActorSystem@localhost:8110/system/sharding/myRegionCoordinator] Singleton manager started singleton actor [akka://MyActorSystem/system/sharding/myRegionCoordinator/singleton]
[INFO][1/3/2023 5:31:48 AM][Thread 0013][akka.tcp://MyActorSystem@localhost:8110/system/sharding/myRegionCoordinator] ClusterSingletonManager state change [Start -> Oldest] Akka.Cluster.Tools.Singleton.Uninitialized
[INFO][1/3/2023 5:31:48 AM][Thread 0003][akka.tcp://MyActorSystem@localhost:8110/system/sharding/myRegionCoordinator/singleton/coordinator] Sharding Coordinator was moved to the active state Akka.Cluster.Sharding.PersistentShardCoordinator+State
info: Microsoft.Hosting.Lifetime[14]
      Now listening on: https://localhost:61877
info: Microsoft.Hosting.Lifetime[14]
      Now listening on: http://localhost:61878
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
      Content root path: G:\git\Akka.Hosting\src\Examples\Akka.Hosting.SimpleDemo\
[ERROR][1/3/2023 5:31:49 AM][Thread 0013][akka://MyActorSystem/system/sharding/myRegion/3/0HMND9F7KSI93%3A00000001] Error while creating actor instance of type Akka.Hosting.SimpleDemo.EchoActor with 0 args: ()
Cause: [akka://MyActorSystem/system/sharding/myRegion/3/0HMND9F7KSI93%3A00000001#345915985]: Akka.Actor.ActorInitializationException: Exception during creation
 ---> System.TypeLoadException: Error while creating actor instance of type Akka.Hosting.SimpleDemo.EchoActor with 0 args: ()
 ---> System.InvalidOperationException: Cannot resolve scoped service 'Akka.Hosting.SimpleDemo.IReplyGenerator' from root provider.
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteValidator.ValidateResolution(Type serviceType, IServiceScope scope, IServiceScope rootScope)
   at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.ConstructorMatcher.CreateInstance(IServiceProvider provider)
   at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.CreateInstance(IServiceProvider provider, Type instanceType, Object[] parameters)
   at Akka.DependencyInjection.ServiceProviderActorProducer.Produce()
   at Akka.Actor.Props.NewActor()
   --- End of inner exception stack trace ---
   at Akka.Actor.Props.NewActor()
   at Akka.Actor.ActorCell.CreateNewActorInstance()
   at Akka.Actor.ActorCell.<>c__DisplayClass116_0.<NewActor>b__0()
   at Akka.Actor.ActorCell.UseThreadContext(Action action)
   at Akka.Actor.ActorCell.NewActor()
   at Akka.Actor.ActorCell.Create(Exception failure)
   --- End of inner exception stack trace ---
   at Akka.Actor.ActorCell.Create(Exception failure)
   at Akka.Actor.ActorCell.SysMsgInvokeAll(EarliestFirstSystemMessageList messages, Int32 currentState)
[INFO][1/3/2023 5:31:49 AM][Thread 0003][akka://MyActorSystem/system/sharding/myRegion/3/0HMND9F7KSI93%3A00000001] Message [String] from [akka://MyActorSystem/temp/g] to [akka://MyActorSystem/system/sharding/myRegion/3/0HMND9F7KSI93%3A00000001#345915985] was not delivered. [1] dead letters encountered. If this is not an expected behavior then [akka://MyActorSystem/system/sharding/myRegion/3/0HMND9F7KSI93%3A00000001#345915985] may have terminated unexpectedly. This logging can be turned off or adjusted with configuration settings 'akka.log-dead-letters' and 'akka.log-dead-letters-during-shutdown'.

Steps to reproduce the behavior:
Clone -> Build -> Set Akka.Hosting.SimpleDemo as startup project. -> F5

A clear and concise description of what you expected to happen. -> There should be no exceptions?!

Are you running on Linux? Windows? Docker? Which version of .NET? => Windows 2019, .net 7.101

Akka.Hosting.TestKit: `AwaitAssertAsync` only runs once

Version Information
Version of Akka.NET? 1.5.0
Which Akka.NET Modules? Akka.Hosting.TestKit

Describe the bug

await AwaitAssertAsync(async () =>
{
    var r = await testActorRef.Ask<string>(new MyTestActor.GetData(), TimeSpan.FromMilliseconds(100));
    r.Should().Be("BackgroundService started");
}, RemainingOrDefault, TimeSpan.FromMilliseconds(150));

The above assertion runs once and then quits.

"There is no active ActorContext" exception in Context.System while running tests

Version Information
Version of Akka.NET? 1.5.10
Which Akka.NET Modules? Akka.Hosting

Describe the bug
There is no active ActorContext exception in Context.System while running tests
(when trying to create actor props with the DependencyResolver)

To Reproduce
Steps to reproduce the behavior:

  1. Clone https://github.com/gunters63/DIPropsFail
  2. Run tests

Expected behavior
Test is green

Actual behavior

There is no active ActorContext, this is most likely due to use of async operations from within this actor.
   at Akka.Actor.ActorBase.get_Context()
   at Akka.Actor.UntypedActor.get_Context()
   at DiPropsFail.DiPropsFailTest.NonRootActorWithDi.Props() in D:\temp\DIPropsFail\DIPropsFail\DiPropsFailTest.cs:line 36
   at DiPropsFail.DiPropsFailTest.NonRootActorWithDiTest() in D:\temp\DIPropsFail\DIPropsFail\DiPropsFailTest.cs:line 20

Screenshots
image

Environment
Rider unter Windows 11

Additional context
The strange things is:

  • sometimes the test is green when I run it in a bigger test suite together with other tests
  • when I copy this exact unit test file into the Akka.Hosting.TestKit.Tests folder of a cloned repo it works reliably.

I suspect this is maybe a racing condition.

Akka.Cluster.Hosting & Serialization

Version Information
Version of Akka.NET? 1.4.48
Which Akka.NET Modules? Akka.Cluster, Akka.Cluster.Hosting, Akka.Logger.NLog

Describe the bug
This is the message during deserialization of custom message in a cluster between two nodes.

Deserialization failed for message with serializer id [1] and manifest []. Transient association error (association remains live). Object reference not set to an instance of an object.. Serializer Id [1] is used to instantiate [Akka.Serialization.NewtonSoftJsonSerializer, Akka]. You can add it by adding a fallback to your ActorSystem configuration by using [ConfigurationFactory.Default()]. It is also automatically injected into your configuration when you call [ActorSystem.Create()].

To Reproduce
Simply create two node with the same application and ask/tell messages between them. Configure Actors using Akka.Cluster.Hosting

Links to working reproductions on Github / Gitlab are very much appreciated

Expected behavior
Custom message deserialized

Actual behavior
The error above

Screenshots
null

Environment
Linux

Additional context
null

WithLoggerFactory unable to load logger

Version Information
Akka 1.4.39
Akka.hosting 0.4.0

Describe the bug
Using WithLoggerFactory throws Akka.Configuration.ConfigurationException:

To Reproduce
Create a new console application using the dotnet cli

> dotnet new console

Install dependencies

    <ItemGroup>
      <PackageReference Include="Akka" Version="1.4.39" />
      <PackageReference Include="Akka.Hosting" Version="0.4.0" />
      <PackageReference Include="Microsoft.Extensions.Hosting" Version="3.0.0" />
    </ItemGroup>

Update program.cs

using var host = CreateHostBuilder(args)
    .UseConsoleLifetime().Build();

await host.StartAsync();

var actorSystem = host.Services.GetRequiredService<ActorSystem>();

Console.ReadLine();

await actorSystem.Terminate();
await actorSystem.WhenTerminated;
await host.StopAsync();

static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureServices(services =>
        {
            services.AddAkka("AkkaSandbox", (configBuilder, provider) =>
            {
                configBuilder.AddHocon("akka.loglevel = DEBUG")
                    .WithLoggerFactory();
            });
        });

Error message

crit: Akka.Hosting.AkkaHostedService[0]
      Unable to start AkkaHostedService - shutting down application
Akka.Configuration.ConfigurationException: Logger [Akka.Hosting.Logging.LoggerFactoryLogger, Akka.Hosting] specified in config cannot be loaded: System.AggregateException: One or more errors occurred. (Timeout after 00:00:05 seconds)
 ---> Akka.Actor.AskTimeoutException: Timeout after 00:00:05 seconds
   --- End of inner exception stack trace ---
   at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)
   at System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification)
   at System.Threading.Tasks.Task`1.get_Result()
   at Akka.Event.LoggingBus.AddLogger(ActorSystemImpl system, Type loggerType, LogLevel logLevel, String loggingBusName, TimeSpan timeout)
   at Akka.Event.LoggingBus.StartDefaultLoggers(ActorSystemImpl system)
 ---> System.AggregateException: One or more errors occurred. (Timeout after 00:00:05 seconds)
 ---> Akka.Actor.AskTimeoutException: Timeout after 00:00:05 seconds
   --- End of inner exception stack trace ---
   at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)
   at System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification)
   at System.Threading.Tasks.Task`1.get_Result()
   at Akka.Event.LoggingBus.AddLogger(ActorSystemImpl system, Type loggerType, LogLevel logLevel, String loggingBusName, TimeSpan timeout)
   at Akka.Event.LoggingBus.StartDefaultLoggers(ActorSystemImpl system)
   --- End of inner exception stack trace ---
   at Akka.Event.LoggingBus.StartDefaultLoggers(ActorSystemImpl system)
   at Akka.Actor.LocalActorRefProvider.Init(ActorSystemImpl system)
   at Akka.Actor.Internal.ActorSystemImpl.Start()
   at Akka.Actor.ActorSystem.CreateAndStartSystem(String name, Config withFallback, ActorSystemSetup setup)
   at Akka.Actor.ActorSystem.Create(String name, ActorSystemSetup setup)
   at Akka.Hosting.AkkaConfigurationBuilder.<>c.<ActorSystemFactory>b__28_0(IServiceProvider sp)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitRootCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine.<>c__DisplayClass1_0.<RealizeService>b__0(ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
   at Akka.Hosting.AkkaHostedService.StartAsync(CancellationToken cancellationToken)

Environment
MacOS Monetery, .NET 6

IConfiguration To HOCON Adapter always converts all keys to lower-case

Version Information
Version of Akka.NET? 1.5,12
Which Akka.NET Modules?

Describe the bug
In HOCON I can configure Akka.Net to use the Hyperion serializer like this:

  actor {
    serializers {
      hyperion = "Akka.Serialization.HyperionSerializer, Akka.Serialization.Hyperion"
    }
    serialization-bindings {
      "System.Object" = hyperion
    }
  }

I tried to move my HOCON configuration to ASP.NET IConfiguration (in appsettings.json).
Fist I had a problem with the dot character in "System.Object" because the HOCON adapter treats all keys as potentially dotted paths. I found out I can quote the key like this in my appsettings.json (this should probably be documented):

{
  "akka": {
    "actor": {
      "serializers": {
        "hyperion": "Akka.Serialization.HyperionSerializer, Akka.Serialization.Hyperion"
      },
      "serialization-bindings": {
        "\"System.Object\"": "hyperion"
      }
    }
  }
}

I have still the problem that the HOCON adapter converts all keys to lowercase (see ExpandKey in ConfigurationHoconAdapter.cs). I get the following warning at startup:

[WARNING][08.11.2023 08:29:24.190Z][Thread 0001][ActorSystem(EnsoBackend)] The type name for message/serializer binding 'hyperion' did not resolve to an actual Type: 'system.object'

and if I log the HCON config with "log-config-on-start": true I can see the problem:

image

API changes roadmap for 1.0

This issue thread is made as a discussion ground on what API needs to be changed/added into Akka.Hosting before we're freezing it for 1.0 release. We encourage users to make suggestions in this thread based on their experience in using Akka.Hosting so far.

Currently, Akka.Hosting still need these API addition/changes:

Persistence and Cluster Sharding

These API changes are needed to make persistence be compatible with sharding.

  • Add API to Akka.Cluster.Hosting to allow user to specify a specific persistence plugin for cluster sharding
  • Add API to add a persistence journal/snapshot plugin settings that can be referenced elsewhere. #146
    • Maybe we can expand AkkaPersistenceJournalBuilder for journal settings?
    • If so, we need to add AkkaPersistenceSnapshotBuilder for snapshot settings
    • Persistence plugins Hosting extensions should not use Setup classes, they should inject their HOCON configuration directly.
  • Change the current Akka.Persistence.*.Hosting implementation to not automatically inject themselves as the default persistence plugins #146
  • Change the current Akka.Persistence.*.Hosting API to let their HOCON settings be copied over or renamed to another HOCON block for use with either normal persistence or cluster sharding #146
  • Add a generalized Akka.Persistence.Hosting API to specifically set the akka.persistence.journal.plugin and akka.persistence.snapshot-store.plugin settings. #146

Remoting

  • We will not make remote deployment hosting API

Clustering

  • Expand current API with more options to configure the cluster. Current settings candidates: (#149)
    • min-nr-of-members
    • Per role min-nr-of-members
    • app-version
    • Logging related settings
    • Move SBR into this options class (only the new SBR will be supported)
  • Expand singleton API to enable lease (#150)
  • Expand sharding API to enable lease (#150)

General

  • Make all options class bindable to Microsoft.Extensions.Configuration

Please add guardian-supervisor-strategy tot he Fluent API

We are trying to update our application to use the Fluent API for configuration and after asking about this Aaron suggested creating an issue for it.

We would to be able to configure the following via the Fluent API:

akka
{
actor
{
guardian-supervisor-strategy = "BatchProcessorLibrary.Akka.GuardianSupervisorStrategy, BatchProcessorLibrary"
}
}

Akka.Hosting racy spec failure: `Should_configure_LoggerFactoryLogger`

Version Information
Version of Akka.NET? dev latest
Which Akka.NET Modules? Akka.Hosting core

Describe the bug

Encountered a racy spec failure upon merging #108 into dev

  14:18:20 [ERR] [xUnit.net 00:00:03.96]     Akka.Hosting.Tests.Logging.LoggerConfigEnd2EndSpecs.Should_configure_LoggerFactoryLogger [FAIL]
  14:18:20 [DBG]   Failed Akka.Hosting.Tests.Logging.LoggerConfigEnd2EndSpecs.Should_configure_LoggerFactoryLogger [3 s]
  14:18:20 [DBG]   Error Message:
  14:18:20 [DBG]    Expected _logger.Infos.Where(c => c.Contains("foo")) to contain 1 item(s), but found 0: {empty}.
  14:18:20 [DBG]   Stack Trace:
  14:18:20 [DBG]      at FluentAssertions.Execution.XUnit2TestFramework.Throw(String message)
  14:18:20 [DBG]    at FluentAssertions.Execution.TestFrameworkProvider.Throw(String message)
  14:18:20 [DBG]    at FluentAssertions.Execution.DefaultAssertionStrategy.HandleFailure(String message)
  14:18:20 [DBG]    at FluentAssertions.Execution.AssertionScope.FailWith(Func`1 failReasonFunc)
  14:18:20 [DBG]    at FluentAssertions.Collections.GenericCollectionAssertions`3.HaveCount(Int32 expected, String because, Object[] becauseArgs)
  14:18:20 [DBG]    at Akka.Hosting.Tests.Logging.LoggerConfigEnd2EndSpecs.<Should_configure_LoggerFactoryLogger>b__4_0() in /home/runner/work/Akka.Hosting/Akka.Hosting/src/Akka.Hosting.Tests/Logging/LoggerConfigEnd2EndSpecs.cs:line 67
  14:18:20 [DBG]    at Akka.TestKit.TestKitBase.AwaitAssertAsync(Action assertion, Nullable`1 duration, Nullable`1 interval)
  14:18:20 [DBG]    at Akka.Hosting.Tests.Logging.LoggerConfigEnd2EndSpecs.Should_configure_LoggerFactoryLogger() in /home/runner/work/Akka.Hosting/Akka.Hosting/src/Akka.Hosting.Tests/Logging/LoggerConfigEnd2EndSpecs.cs:line 66
  14:18:20 [DBG] --- End of stack trace from previous location ---
  14:18:20 [DBG]   Standard Output Messages:

To Reproduce

N/A - appears to be racy.

Akka.Remote.Hosting doesn't support `public-hostname` correctly

Version Information
Version of Akka.NET? 0.2.0
Which Akka.NET Modules? Akka.Remote.Hosting

Describe the bug

When using the following configuration:

services.AddAkka("RemoteSys", (builder, provider) =>
{
    builder.WithRemoting("0.0.0.0", 0, "localhost");
});

Akka.Remote will bind to 0.0.0.0 as its public address instead of localhost.

To Reproduce

Sending a PR for this

Expected behavior

Akka.Remote should bind to 0.0.0.0 under the hood, but advertise its public address as localhost.

Actual behavior

Akka.Remote binds to 0.0.0.0 and advertises it as its public address.

BackgroundService DI of IRequiredActor for reference to an Actor fails with 'No actor registered'

Version Information
Akka.Hosting 1.0.2

Describe the bug
Creating a Microsoft.Extensions.Hosting.BackgroundService with a DI fails to inject a IRequiredActor interface with the error of Akka.Hosting.MissingActorRegistryEntryException: 'No actor registered for key <ActorName>'

To Reproduce
The simplest code reproduction of this error is

using Akka.Actor;
using Akka.Hosting;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddHostedService<ThingRunningInTheBackground>();

builder.Services.AddAkka("mysystem", configurationBuilder =>
{
    configurationBuilder.WithActors((system, registry, resolver) =>
    {
        var leadActor = system.ActorOf(Props.Create(() => new LeadActor()));

        registry.TryRegister<LeadActor>(leadActor);
    });
});

var app = builder.Build();
app.MapGet("/", () => "Hello World!");
app.Run();

public class LeadActor : ReceiveActor
{
    public LeadActor()
    {
        Receive<string>(Console.Write);
    }
}

public class ThingRunningInTheBackground : BackgroundService
{
    private readonly IActorRef _actor;

    public ThingRunningInTheBackground(IRequiredActor<LeadActor> actor)
    {
        _actor = actor.ActorRef;
    }
    protected override Task ExecuteAsync(CancellationToken stoppingToken)
    {
        throw new NotImplementedException();
    }
}

Environment
Windows 10
Net 7.0

Discord Discussions
Chatting on discord about this problem @Aaronontheweb

What the problem is

I'm not sure how to work around this problem inside IRequiredActor just yet
but the issue is that all of your actors are started in another IHostedService managed by Akka.NET
and that hasn't had a chance to run and populate the ActorRegistry by the time your BackgroundService starts
so until I come up with a way to force IRequiredActor to do this behind the scenes (probably by blocking, unless there's an await-able way of doing this)

The current solution to the approach

so the solution to this is to have the ActorRegistry injected into your BackgroundService and then call ActorRegistry.GetAsync on it
that call will return a Task you can await on
and the task will be completed as soon as the actor gets added to the registry
which should only be a on the order of 100s of milliseconds

Tweet by Aaron asking about some approachs
https://twitter.com/Aaronontheweb/status/1623064967724298251

Taking the above simple reproduction this below code works noting the injection of ActorRegistry into the constructor and using the _actorRegistry.GetAsync to get the actor reference.

using Akka.Actor;
using Akka.Hosting;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHostedService<ThingRunningInTheBackgroundUsingRegistry>();

builder.Services.AddAkka("mysystem", configurationBuilder =>
{
    configurationBuilder.WithActors((system, registry, resolver) =>
    {
        var leadActor = system.ActorOf(Props.Create(() => new LeadActor()));

        registry.TryRegister<LeadActor>(leadActor);
    });
});

var app = builder.Build();
app.MapGet("/", () => "Hello World!");
app.Run();

public class LeadActor : ReceiveActor
{
    public LeadActor()
    {
        Receive<string>(Console.Write);
    }
}

public class ThingRunningInTheBackgroundUsingRegistry : BackgroundService
{
    private IActorRef? _actorReference;
    private readonly ActorRegistry _actorRegistry;

    public ThingRunningInTheBackgroundUsingRegistry(ActorRegistry actorRegistry)
    {
        _actorRegistry = actorRegistry;
    }
    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        _actorReference = await _actorRegistry.GetAsync<LeadActor>(stoppingToken);

        _actorReference.Tell("Message");
    }
}

Akka.Hosting.TestKit: default `DisposeAsync` implementation can throw `OperationCancelledException` and erroneously fail test

Version Information
Version of Akka.NET? 1.5.6.1 and 1.5.7
Which Akka.NET Modules? Akka.Hosting.TestKit

Describe the bug

   at System.Threading.CancellationToken.ThrowOperationCanceledException()
   at System.Threading.CancellationToken.ThrowIfCancellationRequested()
   at Microsoft.Extensions.Hosting.Internal.Host.StopAsync(CancellationToken cancellationToken)
   at Akka.Hosting.TestKit.TestKit.DisposeAsync()

To Reproduce

Difficult to reproduce, but it appears to happen when tests run and exit very quickly - here's an example from the Phobos test suite that causes this issue:

public class AkkaHostingConfigSpecs : TestKit
    {
        protected override void ConfigureAkka(AkkaConfigurationBuilder builder, IServiceProvider provider)
        {
            builder.WithPhobos(AkkaRunMode.AkkaCluster);
        }

        [Fact]
        public void ShouldEnforceDefaultConfig()
        {
            Sys.Settings.EmitActorTelemetry.Should().BeTrue();
        }
    }

Actual behavior

Test should exit cleanly

Expose AskTimeout configuration in Akka.Hosting

Is your feature request related to a problem? Please describe.
Akka.Hosting is created to 'get rid of' hocon configuration files to have a more seamless and easy model of setting up Akka.NET. Right now, in our solution, we only need hocon to configure the ask-timeout setting.

Describe the solution you'd like
Expose ask-timeout also via Akka.Hosting so that we can completely remove our .hocon files.

Akka.Hosting works really great so it helps if more options are getting exposed.

NUKE no longer publishes `CHANGELOG.md` notes to GitHub Release

Since merging #74 GitHub Release flows no longer propagate the release notes typed into CHANGELOG.md into GitHub Releases - we noticed this yesterday with https://github.com/akkadotnet/Akka.Hosting/releases/tag/0.4.0. The release notes for 0.4.0 were auto-generated by GitHub itself, rather than using the notes that @Arkatufus typed up. This is a regression that needs to be fixed in this project and in all of https://github.com/petabridge/petabridge-dotnet-new that have been upgraded to the latest NUKE.

Akka.Persistence: Add support for adding `IEventAdapter`

Is your feature request related to a problem? Please describe.

It'd be great if we had a strongly typed way of adding read / write IEventAdapter instances to Akka.Persistence through Akka.Hosting.

Describe the solution you'd like

We'd need a stand-alone Akka.Persistence.Hosting binary since the event adapters aren't specific to any journal implementation, and it'd need to have a method like this:

builder.WithEventAdapter<TAdapter>(...) where TAdapter:IEventAdapter

Behind the scenes this could build up the appropriate HOCON, extracted from the strongly typed arguments, without needing to add any new Setup types to Akka.NET.

Describe alternatives you've considered
A clear and concise description of any alternative solutions or features you've considered.

Please add failure-detector to the fluent API

We are trying to update our application to use the Fluent API for configuration and after asking about this Aaron suggested creating an issue for it.

We would like to be able to configure the following via the Fluent API

cluster
{
failure-detector
{
implementation-class="Akka.Remote.DeadlineFailureDectector.Akka.Remote"
acceptable-heartbeat-pause = 300s
heartbeat-interval = 2s
}
}

Non-zero exit code on cluster failure

Is your feature request related to a problem? Please describe.
We are hosting Akka.Cluster in Windows services. In order for the service to automatically restart after a cluster failure it needs to set a non-zero exit code.

Describe the solution you'd like
A hook or event before StopApplication is called from AkkaHostedService.

Describe alternatives you've considered
Akka.Hosting could set the exit code in failure scenarios, but might be more inflexible.

Additional context
I'd be happy to create a pull request if any of the above sounds like a reasonable solution.

Tighter integration with Extensions.DependencyInjection

Is your feature request related to a problem? Please describe.
I'm trying out Akka.Hosting in my ASP.NET application and for most parts I'm very happy and didnt need to use any HOCON fine tuning. As a ASP.NET user I'm a bit confused at the state of DependencyInjection when using AddAkka and ActorRegistry. From my past experience with Akka.net I know I can use the DependencyResolver and build props using it to spawn an actor using constructor injection but I have no reference to the DependencyResolver (or the Actor System) in my AddAkka call, right?

Let's say I want to add a cluster singleton via WithSingleton:

services.AddAkka(name, (akka, provider) => {
   ...
   akka.WithSingleton<ClusterCronJobSchedulerActor>("cron-scheduler", Props.Create<ClusterCronJobSchedulerActor>());
   ...
});

Here I would like to use the "DI-enabled" props via DependencyResolver but I have no reference to the ActorSystem to create my DependencyResolver. I could use WithActors but this defeats the purpose of WithSingleton. Am I doing something wrong here?

Describe the solution you'd like
My ideal solution would be one where I didn't have to think about when to use DependencyResolver. My thinking is, when using Akka.Hosting the possibility is high that I also want to be integrated in my ServiceProvider but I expect this isn't possible because we can't just assume constructor injection everywhere as this would make actor creation slower for simple props.

Describe alternatives you've considered
My exact problem could be solved by either including ActorSystem/DependencyResolver somewhere in the AddAkka-lambda (akka.System? akka.DependencyResolver? Is the system already available when in building phase?) or providing a factory function everywhere it might be needed (Func<ActorSystem, Props>) to use DependencyResolver.Get(system).

This problem also exists with WithShardRegion calls.

Add Support for `Microsoft.Extensions.Diagnostics.IHealthCheck`?

Is your feature request related to a problem? Please describe.

We have a couple of different implementations for health-checks floating around in Akka.NET - all of them expressing the same idea: let the platform supervisor (i.e. Kubernetes, Cloud, process monitor etc) know when the Akka.NET service is degraded as a result of common problems:

  • Inability to join cluster;
  • Akka.Persistence being unavailable;
  • Failure to start ActorSystem (i.e. an Akka.Remote port binding failure.)

The first implementation is one I rolled myself a few years ago - and it works well enough: https://github.com/petabridge/akkadotnet-healthcheck - however, it definitely suffers from byte rot to some degree and there isn't a "one liner" way of integrating it with something like ASP.NET.

The second implementation, which is not fully baked as far as I know, is inside Akka.Management's HTTP APIs: https://github.com/akkadotnet/Akka.Management/tree/dev/src/management/Akka.Management#exposed-rest-api-endpoints - this takes a hard dependency on ASP.NET and you basically have to ship your Akka.NET application with a lightweight HTTP API on top of it. Plus, I don't think those checks are configurable beyond whether or not a cluster has been formed.

Describe the solution you'd like

Micrsoft.Extensions.Diagnostics.IHealthCheck provides a somewhat standard way of plugging healthcheck infrastructure together through the HealthCheckService class. Since Akka.Hosting is already built around the Microsoft.Extensions.[DI|Hosting|Configuration] libraries anyway, why not support having pluggable healthchecks from services like Akka.Management or Akka.Persistence available as options on the builder interface here?

Describe alternatives you've considered

Making Akka.Management the end-all-be-all for this.

pbm hosting in .NET 4.7.2 fsi (F# 8) of SSIS script task

Version of Akka.NET? .net 4.7.2 in SSIS script task
Which Akka.NET Modules? Akka.Hosting &

To Reproduce
Create a HostBuilder and start it via F# fsiEvaluationSession hosted in SSIS 2022 script task (.NET 4.7.2) with .AddPetabridgeCmd

Expected behavior
The pbm client should easily connect pbm host, but not.

Actual behavior
The same F# script would successfully create the (web) service and ActorSystem would bring pbm host started in normal Fsi session.
But if the script is execut ed in a fsiEvaluationSession hosted in SSIS, the ActorSystem would not bring pbm host started with HOCON correctly configured.

Environment
Windows Server 2022/SQL Server 2022 (SSIS)

Additional context
It must to manually start pbm with

let cmd = PetabridgeCmd.Get asys
cmd.Start()

Add support for Akka.Logger.Serilog.Hosting

Is your feature request related to a problem? Please describe.
I'm successfully using the hosting package, but I still have to configure Serilog in hocon, and ensure that the Akka.Logger.Serilog package is added to the project.

Describe the solution you'd like
Add a project for Akka.Logger.Serilog.Hosting that includes the dependency on Akka.Logger.Serilog, and has a builder extension method for WithSerilogLogger(string loglevel)

Describe alternatives you've considered
N/A

Additional context
A simple extension method could be added that sets the logger in the hocon

public static class AkkaLoggerSerilogHostingExtensions
    {
        /// <summary>
        /// Configures Serilog logger.
        /// </summary>
        /// <param name="builder">The builder instance being configured.</param>
        /// <param name="loglevel">Specifies loglevel for <see cref="ActorSystem"/></param>
        /// <returns>The same <see cref="AkkaConfigurationBuilder"/> instance originally passed in.</returns>
        public static AkkaConfigurationBuilder WithSerilogLogger(this AkkaConfigurationBuilder builder, string loglevel)
        {
            if (!string.IsNullOrEmpty(loglevel))
            {
                builder.AddHocon($"akka {{ loglevel={loglevel},  loggers=[\"Akka.Logger.Serilog.SerilogLogger, Akka.Logger.Serilog\"]}}", HoconAddMode.Prepend);
            }

            return builder;
        }
    }

I have this code running, so let me know if you'd like me to send a PR.

Make most major Akka.NET configuration sections parseable via Microsoft.Extensions.Configuration

    Here's what we have to do in the current stable version of Akka.Hosting:
var akkaSection = context.Configuration.GetSection("Akka");

// maps to environment variable Akka__ClusterIp
var hostName = akkaSection.GetValue<string>("ClusterIp", "localhost");

// maps to environment variable Akka__ClusterPort
var port = akkaSection.GetValue<int>("ClusterPort", 0);

var seeds = akkaSection.GetValue<string[]>("ClusterSeeds", new[] { "akka.tcp://SqlSharding@localhost:7918" })
    .Select(Address.Parse)
    .ToArray();

It would be amazing if we could just do this instead (and if we decide to go down this route, we should write a unit test that looks like this):

appsettings.json

{
    "Logging": {
        "LogLevel": {
            "Default": "Debug",
            "System": "Information",
            "Microsoft": "Information"
        }
    },
    "Akka": {
        "RemoteOptions":{
            "Hostname": "localhost",
            "Port": 8081,
            "PublicHostname": "localhost",
            "PublicPort": 8081
        },
        "ClusterOptions": {
            "SeedNodes": "akka.tcp://ClusterSystem@localhost:8081",
            "Roles": ["backend"]
        }
    }
}

program.cs

var akkaSection = context.Configuration.GetSection("Akka");
var clusterConfig = akkaSection.Get<ClusterOptions>(); // ideally, this should work

We've not really stated this as an explicit goal for the project before, but in the context of our "pit of success" mission for this library I think it's probably worth doing before we ship 1.0. What do you think?

Originally posted by @Aaronontheweb in #149 (comment)

`.WithShardRegion` does not add default configuration for cluster sharding

Version Information
Version of Akka.Hosting? 1.0.3
Which Akka.Hosting Modules? Akka.Cluster.Hosting

Describe the bug
IHost fails to load with .WithShardRegion because singleton default configuration was not added

To Reproduce

builder
    .ConfigureLoggers(logger =>
    {
        logger.LogLevel = LogLevel.InfoLevel;
        logger.AddLoggerFactory();
    })
    .AddHocon(@"
akka.cluster.min-nr-of-members = 3
akka.cluster.sharding.snapshot-after = 20
akka.actor.ask-timeout = 3s", HoconAddMode.Prepend)
    .WithCustomSerializer(
        serializerIdentifier: "customSerializer",
        boundTypes: new [] {typeof(CustomShardedMessage)}, 
        serializerFactory: system => new CustomSerializer(system))
    .WithRemoting("localhost", port)
    .WithClustering()
    .WithShardRegion<ShardRegion>(
        "test",
        EntityActor.Props,
        new MessageExtractor(), 
        new ShardOptions
        {
            RememberEntities = false,
            StateStoreMode = StateStoreMode.Persistence
        })
    .WithJournal(journalId, journalBuilder =>
    {
        journalBuilder.AddWriteEventAdapter<EventAdapter>(
            eventAdapterName: "customMessage",
            boundTypes: new[] { typeof(int), typeof(string) });
    });

Throws an NRE from inside ClusterShardingSettings.Create() because akka.cluster.sharding.coordinator-singleton does not exist

Adding .WithFallback(ClusterSharding.DefaultConfig()).WithFallback(ClusterSingletonManager.DefaultConfig()); into my config fixes the issue.

Custom Serializer setup not propagating to Persistence

Version Information
Akka - v1.4.43
Akka.Hosting - v0.4.3
Akka.Persistence.SqlServer.Hosting - v0.4.3
Akka.Serialization.Hyperion - v1.4.43

Describe the bug
When setting up Hyperion as the default serializer via Akka.Hosting configuration, persistence still uses Json as the default serializer and has to be configured separately to use Hyperion.

To Reproduce
I used a configuration similar to the following:

        services.AddAkka("actor-system", (configurationBuilder, _) =>
        {
            configurationBuilder
                .WithRemoting("localhost", 7910)
                .WithClustering(new ClusterOptions() { Roles = new[] { "Coordinator-Role" }, SeedNodes = Address[] { Address.Parse("akka.tcp://actor-system@localhost:7910") } })
                .WithSqlServerPersistence("Server=localhost,1433; Database=Akka; User Id=sa; Password=[password];")
                .WithCustomSerializer("hyperion", new[] { typeof(object) }, system => new HyperionSerializer(system));
        {

Expected behavior
When setting up Hyperion as the default serializer, this setting should be propagated through-out the Akka.net modules.

Actual behavior
Json was still the default serializer for persistence.

Screenshots
image

Environment
Windows 11
.Net 6.0

Additional context

ActorRegistry returning ActorRefs.Nobody for not found actors introduces hard-to-find bugs

Is your feature request related to a problem? Please describe.

We currently refactored our project to use Akka.Hosting.
We previously had our own-handrolled solution to register root actors into Microsofts DI so it was nice to see we can just use the new library features now.

We have several root actors, some their child actors need other root actors injected into their constructors (via the DependencyResolver.For(Context.System) pattern).

Those root actors are sometimes used in the PreStart hook, so some root actors have to be available already at construction time of other root actors. This forms a kind of dependency order between our root actors.

If root actors get constructed in the wrong order, those injected root actors have their Actor refs set to Nobody when accessed by IRequiredActor.ActorRef, which means a Tell call will still succeed, but will land in the dead letter queue of course because the sender is Nobody. This was hard to diagnose until we got our construction order of the root actors right.

We made our code now more fail-safe by introducing some extensions which we use i all places where we Tell/Forward messages to injected RequiredActors:

using Akka.Actor;
using Akka.Hosting;
using AtlasCopco.Enso.Actors.Administrator;
using AtlasCopco.Enso.Contracts.Actors;
using Serilog;
using System.Linq;
using System.Reflection;

namespace AtlasCopco.Enso.Actors;

public static class AkkaExtensions
{
    private static void CheckInitialized<TActor>(IRequiredActor<TActor> requiredActor)
    {
        if (requiredActor.ActorRef.Equals(Nobody.Instance))
            throw new ActorRegistryException($"requiredActor {typeof(TActor).Name} not yet constructed!");
    }

    public static void Tell<TActor>(this IRequiredActor<TActor> requiredActor, object message)
    {
        CheckInitialized(requiredActor);
        requiredActor.ActorRef.Tell(message);
    }

    public static void Forward<TActor>(this IRequiredActor<TActor> requiredActor, object message)
    {
        CheckInitialized(requiredActor);
        requiredActor.ActorRef.Forward(message);
    }

    public static void Tell<TActor>(this IRequiredActor<TActor> requiredActor, object message, IActorRef sender)
    {
        CheckInitialized(requiredActor);
        requiredActor.ActorRef.Tell(message, sender);
    }
}

Describe the solution you'd like
A clear and concise description of what you want to happen.

I am not sure why RootActors got registered as Nobody actors in the Registry so the MissingActorRegistryEntryException didn't trigger.

Describe alternatives you've considered

Of course we could use GetAsync() everywhere in our actors for injected root actors (with PipeTo/Self and forwarding message types and handlers), but this would make the code more complicated and messy.

Additional context
Add any other context or screenshots about the feature request here.

Add custom `System.Object` serializer and persistence default serializer peculiarity documentation

Persistence have its own default System.Object serializer settings here:

akka.persistence.journal-plugin-fallback.serializer = json
akka.persistence.snapshot-store-plugin-fallback.serializer = json

https://github.com/akkadotnet/akka.net/blob/3f7d3980fa45565abb824fe5f192f87c1bdde113/src/core/Akka.Persistence/persistence.conf#L119
https://github.com/akkadotnet/akka.net/blob/dev/src/core/Akka.Persistence/persistence.conf#L178

This is a big gotcha for people who does not know about this peculiarity and thinks that Akka persistence would use the custom System.Object serializer they configured with Akka, as shown in issue #127

This needs to be better documented

WithDistributedPubSub throws NullReferenceException

Version Information
Version of Akka.NET? 1.4.28
Which Akka.NET Modules? Akka.Cluster.Hosting 0.3.0

Describe the bug
I'm trying to configure DistributedPubSub using WithDistributedPubSub, but getting System.NullReferenceException

To Reproduce
Steps to reproduce the behavior:

  1. Use WithDistributedPubSub("pub-sub-host") extension method on builder

Expected behavior
A clear and concise description of what you expected to happen.

Configure DistributedPubSub with the role

Actual behavior
What actually happened and how did it differ from your expectations?

Getting the following exception

Unhandled exception. System.NullReferenceException: Object reference not set to an instance of an object.
   at Akka.Configuration.Config.Contains(Config other)
   at Akka.Configuration.Config.WithFallback(Config fallback)
   at Akka.Configuration.Config.GetConfig(String path)
   at Akka.Configuration.Config.GetConfig(String path)
   at Akka.Configuration.Config.GetConfig(String path)
   at Akka.Configuration.Config.GetConfig(String path)
   at Akka.Configuration.Config.GetConfig(String path)
   at Akka.Configuration.Config.GetConfig(String path)
   at Akka.Configuration.Config.GetConfig(String path)
   at Akka.Configuration.Config.GetConfig(String path)
   at Akka.Configuration.Config.GetConfig(String path)
   at Akka.Cluster.Tools.PublishSubscribe.DistributedPubSubSettings.Create(ActorSystem system)
   at Akka.Cluster.Tools.PublishSubscribe.DistributedPubSub..ctor(ExtendedActorSystem system)
   at Akka.Cluster.Tools.PublishSubscribe.DistributedPubSubExtensionProvider.CreateExtension(ExtendedActorSystem system)
   at Akka.Actor.ExtensionIdProvider`1.Akka.Actor.IExtensionId.CreateExtension(ExtendedActorSystem system)
   at Akka.Actor.Internal.ActorSystemImpl.<>c__DisplayClass61_0.<RegisterExtension>b__1()
   at System.Lazy`1.ViaFactory(LazyThreadSafetyMode mode)
   at System.Lazy`1.ExecutionAndPublication(LazyHelper executionAndPublication, Boolean useDefaultConstructor)
   at System.Lazy`1.CreateValue()
   at System.Lazy`1.get_Value()
   at Akka.Actor.Internal.ActorSystemImpl.TryGetExtension(Type extensionType, Object& extension)
   at Akka.Actor.Internal.ActorSystemImpl.GetExtension(IExtensionId extensionId)
   at Akka.Actor.ExtensionIdProvider`1.Get(ActorSystem system)
   at Akka.Actor.ExtensionIdProvider`1.Akka.Actor.IExtensionId.Get(ActorSystem system)
   at Akka.Actor.Internal.ActorSystemImpl.RegisterExtension(IExtensionId extension)
   at Akka.Actor.ActorSystemWithExtensions.WithExtension[T,TI](ActorSystem system)
   at Akka.Cluster.Tools.PublishSubscribe.DistributedPubSub.Get(ActorSystem system)
   at Akka.Cluster.Tools.Client.ClusterClientReceptionist.get_PubSubMediator()
   at Akka.Cluster.Tools.Client.ClusterClientReceptionist.CreateReceptionist()
   at Akka.Cluster.Tools.Client.ClusterClientReceptionist..ctor(ExtendedActorSystem system)
   at Akka.Cluster.Tools.Client.ClusterClientReceptionistExtensionProvider.CreateExtension(ExtendedActorSystem system)
   at Akka.Actor.ExtensionIdProvider`1.Akka.Actor.IExtensionId.CreateExtension(ExtendedActorSystem system)
   at Akka.Actor.Internal.ActorSystemImpl.<>c__DisplayClass61_0.<RegisterExtension>b__1()
   at System.Lazy`1.ViaFactory(LazyThreadSafetyMode mode)
   at System.Lazy`1.ExecutionAndPublication(LazyHelper executionAndPublication, Boolean useDefaultConstructor)
   at System.Lazy`1.CreateValue()
   at System.Lazy`1.get_Value()
   at Akka.Actor.Internal.ActorSystemImpl.TryGetExtension(Type extensionType, Object& extension)
   at Akka.Actor.Internal.ActorSystemImpl.GetExtension(IExtensionId extensionId)
   at Akka.Actor.ExtensionIdProvider`1.Get(ActorSystem system)
   at Akka.Actor.ExtensionIdProvider`1.Akka.Actor.IExtensionId.Get(ActorSystem system)
   at Akka.Actor.Internal.ActorSystemImpl.RegisterExtension(IExtensionId extension)
   at Akka.Actor.Internal.ActorSystemImpl.ConfigureExtensions(IEnumerable`1 extensionIdProviders)
   at Akka.Actor.Internal.ActorSystemImpl.Start()
   at Akka.Actor.ActorSystem.CreateAndStartSystem(String name, Config withFallback, ActorSystemSetup setup)
   at Akka.Actor.ActorSystem.Create(String name, ActorSystemSetup setup)
   at Akka.Hosting.AkkaConfigurationBuilder.<>c.<ActorSystemFactory>b__28_0(IServiceProvider sp)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitRootCache(ServiceCallSite callSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitRootCache(ServiceCallSite callSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitIEnumerable(IEnumerableCallSite enumerableCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitRootCache(ServiceCallSite callSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceProvider.CreateServiceAccessor(Type serviceType)
   at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
   at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
   at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetService[T](IServiceProvider provider)
   at Microsoft.Extensions.Hosting.Internal.Host.StartAsync(CancellationToken cancellationToken)
   at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token)
   at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token)
   at Program.<Main>$(String[] args) in /Users/jblackburn/repos/signify/architecture/architecture.templates/templates/akkaclusterservice/src/akkacluster.Service/Program.cs:line 25
   at Program.<Main>(String[] args)

Environment
Docker, dotnet 6

** Additional Info**
It looks like the hocon config is incorrect akka.cluster.pub-sub, should it be?

middle.AddHocon($"akka.cluster.pub-sub.role = \"{role}\"", HoconAddMode.Prepend);

Add built-in cluster options to `ClusterOptions` class

    It would also be nice to be able to set cluster related config, like minimum members.

Originally posted by @PeterHageus in #106 (comment)

Doing this is contingent upon whether or not the API is workable / easily express-able in C#.

None of these values should be required to start Akka.Cluster via Akka.Hosting.

  • min-nr-members
  • {role}.min-nr-members <-- might be too difficult to express.
  • AppVersion
  • log-info and log-info-verbose

We don't really want to get into stuff like failure detector customization - that should be done in HOCON.

Akka.Cluster.Hosting: `ShardOptions.PassivateIdleEntityAfter` overwrites custom `akka.cluster.sharding.passivate-idle-entity-after` setting in HOCON

Version Information
Version of Akka.NET? v1.5.6
Which Akka.NET Modules? Akka.Cluster.Hosting

Describe the bug

Not 100% if this is a bug or not yet (going off an end-user's report), but if I set

akka.cluster.sharding.passivate-idle-entity-after = 24h #24 hours

In a separate .hocon file added via the AddHoconFile method (with prepending et al done correctly), but if I start any ShardRegion using the default ShardOptions (without specifying ShardOptions.PassivateIdleEntityAfter) I get the following logs:

image

This indicates that we're still using the default 2 minutes setting, and I believe that's because of our default value for ShardOptions here:

public TimeSpan? PassivateIdleEntityAfter { get; set; } = TimeSpan.FromMinutes(2);

To Reproduce

  1. Create ActorSystem with akka.cluster.sharding.passivate-idle-entity-after = 24h
  2. Start ShardRegion using Akka.Hosting;
  3. Check to see if the passivation timeout is 2 minutes instead of 24 hours.

Additional context

We should probably make null the default value here so that way the HOCON values will be used if not user-supplied value is defined.

Akka.Hosting.TestKit: just have `ConfigureLogging` "do the right thing" by default and automatically wire up `ITestOutput`

Is your feature request related to a problem? Please describe.

Each time I write a test I have to remember how to pipe the MSFT Logging, ILoggingAdapter, and the xUnit ITestOutputHelper together and it's very cumbersome.

Describe the solution you'd like

base implementation of protected virtual void ConfigureLogging(ILoggingBuilder builder){} should just do this for me unless I specify otherwise. Maybe even make the ITestOutputHelper a required constructor parameter (breaking change but no one else is using this yet)

Akka.Hosting NRE upon shutdown

Version Information
Version of Akka.NET? 0.2.2
Which Akka.NET Modules? Akka.Cluster.Hosting

Describe the bug

Upon shutdown, Akka.Hosting will sometimes throw the following NullReferenceException:

   at Microsoft.Extensions.Hosting.Internal.Host.StopAsync(CancellationToken cancellationToken)
   at Phobos.Hosting.Tests.EndToEndHostingSpecs.ShouldLaunchPhobosCluster() in D:\a\1\s\src\core\Phobos.Hosting.Tests\EndToEndHostingSpecs.cs:line 265
--- End of stack trace from previous location where exception was thrown ---
----- Inner Stack Trace -----
   at Akka.Actor.ActorSystemWithExtensions.WithExtension[T,TI](ActorSystem system)
   at Akka.Actor.CoordinatedShutdown.Get(ActorSystem sys)
   at Akka.Hosting.AkkaHostedService.StopAsync(CancellationToken cancellationToken)
   at Microsoft.Extensions.Hosting.Internal.Host.StopAsync(CancellationToken cancellationToken)

I believe this is because the ActorSystem was already terminate prior to CoordinatedShutdown being called.

Expected behavior

Should not throw.

Actual behavior

Throws.

Add support for modifying the sql settings in the `WithSqlServerPersistence` method

Is your feature request related to a problem? Please describe.
We are unable to modify the schema-name, table-name and auto-initialize values when I use the .WithSqlServerPersistence() extension method.

Describe the solution you'd like
We would like to be able to modify the schema-name, table-name and auto-initialize values for both the Journal and Snapshot tables when I use the .WithSqlServerPersistence() extension method.

Describe alternatives you've considered
We've tried adding a hocon config for this, like so:

.AddHocon(@"akka.persistence {
	                journal {
                        plugin = ""akka.persistence.journal.sql-server""
	                    sql-server {
                            schema-name = akka
                            auto-initialize = on
                        }
                    }
	                snapshot-store {
                        plugin = ""akka.persistence.snapshot-store.sql-server""
		                sql-server {
                            schema-name = akka
                            auto-initialize = on
                        }
                    }
                }");

But that does not work. The tables are still initialized with dbo as the schema name.

Add Support for `Akka.Persistence.Postgresql.Hosting`?

Is your feature request related to a problem? Please describe.

Akka.Hosting is a big step forward! Right now the out of the box persistence is SQL Server based. It would be nice for the people who run Postgresql to not have to run a separate SQL Server next to it.

Describe the solution you'd like

Create a WithPostgresqlPersistence extension method.

Additional context

Code for the extension methods for Sql Server: https://github.com/akkadotnet/Akka.Hosting/blob/dev/src/Akka.Persistence.SqlServer.Hosting/AkkaPersistenceSqlServerHostingExtensions.cs

The config is probably something like:

Config journalConfiguration = $@"
  akka.persistence {{
    journal {{
      plugin = ""akka.persistence.journal.postgresql""

      postgresql {{
        class = ""Akka.Persistence.PostgreSql.Journal.PostgreSqlJournal, Akka.Persistence.PostgreSql""
        plugin-dispatcher = ""akka.actor.default-dispatcher""
        connection-timeout = 30s
        schema-name = public
        table-name = event_journal
        auto-initialize = off
        timestamp-provider = ""Akka.Persistence.Sql.Common.Journal.DefaultTimestampProvider, Akka.Persistence.Sql.Common""
        metadata-table-name = metadata
        stored-as = json
        sequential-access = off
        use-bigint-identity-for-ordering-column = on
        connection-string = ""{connectionString}""
      }}
    }}
  }}";

Config snapshotStoreConfig = $@"
  akka.persistence {{
    snapshot-store {{
      plugin = ""akka.persistence.snapshot-store.postgresql""

      postgresql {{
        class = ""Akka.Persistence.PostgreSql.Snapshot.PostgreSqlSnapshotStore, Akka.Persistence.PostgreSql""
        plugin-dispatcher = ""akka.actor.default-dispatcher""
        connection-timeout = 30s
        schema-name = public
        table-name = snapshot_store
        auto-initialize = off
        stored-as = json
        sequential-access = off
        connection-string = ""{connectionString}""
      }}
    }}
  }}";

builder.AddSetup(DependencyResolverSetup.Create(provider)) not apply

Version Information
Version of Akka.NET? 1.5.13
Which Akka.NET Modules? Akka.Hosting

Describe the bug
The code did not work, so I reviewed the akka.hosting code.
https://github.com/akkadotnet/Akka.Hosting/blob/dev/src/Akka.Hosting/AkkaConfigurationBuilder.cs#L142-L146

             // don't apply the diSetup
             if (setup is DependencyResolverSetup)
             {
                 return this;
             }

I was hoping that the DependencyResolverSetup setting would work correctly.
Is there a reason why this code doesn't do anything?

To Reproduce
Steps to reproduce the behavior:
My Code.

        services.AddAkka(appConfig.Name, (builder, provider) =>
        {
            var config = ConfigurationFactory.ParseString(@"...");
            builder.AddHocon(config, HoconAddMode.Prepend)
                .AddSetup(DependencyResolverSetup.Create(provider));
            // skip

Links to working reproductions on Github / Gitlab are very much appreciated

Expected behavior
I expected

Caller

[ApiController]
public class TestController
{
    private readonly IServiceProvider _sp;
    private readonly ActorSystem _system;

    public TestController(ActorSystem system,
        IServiceProvider sp)
    {
        _system = system;
        _sp = sp;
    }

    [HttpGet("/test")]
    public async Task<string> Test()
    {
        var address = Address.Parse("akka.tcp://...@localhost:5011");
        var props = EchoActor.Props(_system)
            .WithDeploy(new Deploy(new RemoteScope(address)));
        var actorRef = _system.ActorOf(props);
        var str = await actorRef.Ask<Response>(new Request("HELLO"));

        return str.Message;
    }
}

Callee

public class EchoActor : ReceiveActor
{
    private readonly IServiceProvider _sp;
    private readonly ILoggingAdapter _logger = Context.GetLogger();
    
    public EchoActor(IServiceProvider sp)
    {
        _sp = sp;
        Receive<Request>(OnReceiveEcho);
    }

    public static Props Props(ActorSystem actorSystem)
    {
        var props = DependencyResolver.For(actorSystem).Props<EchoActor>();
        return props;
    }

Actual behavior
What actually happened and how did it differ from your expectations?

[ERROR][10/29/2023 17:15:20.566Z][Thread 0021][akka.tcp://...@localhost:5011/remote/akka.tcp/r...@localhost:5001/user/$b] Error while creating actor instance of type ....AspNetCore.Actors.EchoActor with 0 args: ()
Cause: [akka.tcp://...@localhost:5011/remote/akka.tcp/...@localhost:5001/user/$b#270112165]: Akka.Actor.ActorInitializationException: Exception during creation
 ---> System.TypeLoadException: Error while creating actor instance of type ....AspNetCore.Actors.EchoActor with 0 args: ()
 ---> System.MissingMethodException: Constructor on type '....AspNetCore.Actors.EchoActor' not found.
   at System.RuntimeType.CreateInstanceImpl(BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture)
   at Akka.Actor.Props.ActivatorProducer.Produce()
   at Akka.Actor.Props.NewActor()
   --- End of inner exception stack trace ---
   at Akka.Actor.Props.NewActor()
   at Akka.Actor.ActorCell.CreateNewActorInstance()
   at Akka.Actor.ActorCell.<>c__DisplayClass116_0.<NewActor>b__0()
   at Akka.Actor.ActorCell.UseThreadContext(Action action)
   at Akka.Actor.ActorCell.NewActor()
   at Akka.Actor.ActorCell.Create(Exception failure)
   --- End of inner exception stack trace ---
   at Akka.Actor.ActorCell.Create(Exception failure)
   at Akka.Actor.ActorCell.SysMsgInvokeAll(EarliestFirstSystemMessageList messages, Int32 currentState)

Screenshots
If applicable, add screenshots to help explain your problem.

Environment
Are you running on Linux? Windows? Docker? Which version of .NET?
.NET 7

Additional context
Add any other context about the problem here.

Akka.Hosting: return non-zero exit code when `CoordinatedShutdown` is invoked due to error'd reasons

Is your feature request related to a problem? Please describe.

In order to enable process supervision on platforms like Windows Services to properly restart an Akka.Hosting / IHost`-powered application, we need to return a non-zero exit code when the application exits improperly.

In many cases, things are shutdown for normal reasons - however, due to the CoordinatedShutdown.Reason property we can generally determine cases where the process may not have shut down cleanly:

Describe the solution you'd like

We should return a non-zero exit code when one of those two types is returned during the method below:

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

Describe alternatives you've considered

It might be worth considering extending the CoordinatedShutdown.Reason class to include an IsError property that would indicate whether or not we should log a non-zero exit code and incorporate this functionality directly into CoordinatedShutdown instead, but I think that might be a bit too prescriptive.

`WithCustomSerializer` needs to add ability to specify serialization identifier

Version Information
Version of Akka.NET? 1.0.1
Which Akka.NET Modules? Akka.Hosting

Describe the bug

One thing that Akka.Hosting can't currently do is specify the akka.actor.serialization-identifiers section of HOCON:

akka.actor{
   # This is to get the manifest back in the event journal
            serializers {
              json2 = "JsonSerializerWithManifest, MyInfrastructure"
            }

            serialization-bindings {
              "System.Object" = json2
            }

            serialization-identifiers {
              "JsonSerializerWithManifest, MyInfrastructure" = 410
            }
}

With the current WithCustomerSerializer method we can't specify this - instead we have to rely on the serializer hard-coding it by overriding the Serializer.Identifer property

.WithCustomSerializer("json2", new[]{ typeof(object) }, system => new JsonSerializerWithManifest(system))

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.