diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 67cd2c31f2e..9657b53e17b 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,7 +1,25 @@ -#### 1.5.32 November 12th 2024 #### +#### 1.5.33 December 4th 2024 #### *Placeholder for nightlies* +#### 1.5.32 December 4th 2024 #### + +Akka.NET v1.5.32 is a maintenance release that addresses several bugs. + +* [Cluster.Tools: Deprecate ClusterSingleton.Init() method](https://github.com/akkadotnet/akka.net/pull/7387) +* [Remote: Ensure RemoteActorRef are serialized correctly when using multiple transports](https://github.com/akkadotnet/akka.net/pull/7393) +* [Sharding: Harden event-sourced RememberEntities infrastructure against transient persistence failures](https://github.com/akkadotnet/akka.net/pull/7401) + +To [see the full set of changes in Akka.NET v1.5.32, click here](https://github.com/akkadotnet/akka.net/milestone/115?closed=1). + +3 contributors since release 1.5.31 + +| COMMITS | LOC+ | LOC- | AUTHOR | +|---------|------|------|---------------------| +| 8 | 750 | 350 | Aaron Stannard | +| 5 | 505 | 15 | Gregorius Soedharmo | +| 1 | 2 | 2 | Ran Trifon | + #### 1.5.31 November 11th 2024 #### Akka.NET v1.5.31 is a maintenance release that addresses several bugs and added new features. diff --git a/src/contrib/dependencyinjection/Akka.DependencyInjection.Tests/ActorTestServices.cs b/src/contrib/dependencyinjection/Akka.DependencyInjection.Tests/ActorTestServices.cs new file mode 100644 index 00000000000..3f5f84736c6 --- /dev/null +++ b/src/contrib/dependencyinjection/Akka.DependencyInjection.Tests/ActorTestServices.cs @@ -0,0 +1,109 @@ +// ----------------------------------------------------------------------- +// +// Copyright (C) 2009-2024 Lightbend Inc. +// Copyright (C) 2013-2024 .NET Foundation +// +// ----------------------------------------------------------------------- + +using System; +using System.Threading; +using System.Threading.Tasks; +using Akka.Actor; +using Akka.Configuration; +using Akka.Dispatch; +using Akka.TestKit; +using Akka.Util.Internal; +using Microsoft.Extensions.Hosting; + +namespace Akka.DependencyInjection.Tests; + +internal class TestDiActor : ReceiveActor +{ + public static readonly AtomicCounter Counter = new(0); + + public TestDiActor(InjectedService injected) + { + long count = Counter.GetAndIncrement(); + Receive(_ => Sender.Tell(new Message { Value = injected.Message, Counter = count })); + } +} + +internal class InjectedEchoActor : ReceiveActor +{ + public InjectedEchoActor(InjectedService injected, string thing) + { + Receive(str => Sender.Tell(new Message { Value = injected.Message + thing, Counter = 0 })); + Receive(i => Sender.Tell(new Message { Value = injected.Message + thing, Counter = 0 })); + } +} + +internal class Message +{ + public string Value { get; set; } + public long Counter { get; set; } +} + +internal class GetMessage +{ + public static readonly GetMessage Instance = new(); + + private GetMessage() + { + } +} + +internal class InjectedService +{ + public string Message => "I was injected"; +} + +internal class CustomMailbox : UnboundedPriorityMailbox +{ + public CustomMailbox(Settings settings, Config config) : base(settings, config) + { + } + + protected override int PriorityGenerator(object message) + { + return message switch + { + string => 1, + int => 2, + _ => 3 + }; + } +} + +internal class AkkaService : IHostedService +{ + public const string CustomMailboxName = "custom-mailbox"; + + private readonly Config _customMailboxHocon = $$""" + custom-mailbox { + mailbox-type = "{{typeof(CustomMailbox).AssemblyQualifiedName}}" + } + """; + + public ActorSystem ActorSystem { get; private set; } + + private readonly IServiceProvider _serviceProvider; + + public AkkaService(IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + } + + public Task StartAsync(CancellationToken cancellationToken) + { + var setup = DependencyResolverSetup.Create(_serviceProvider) + .And(BootstrapSetup.Create().WithConfig(_customMailboxHocon.WithFallback(TestKitBase.DefaultConfig))); + + ActorSystem = ActorSystem.Create("TestSystem", setup); + return Task.CompletedTask; + } + + public async Task StopAsync(CancellationToken cancellationToken = default) + { + await ActorSystem.Terminate(); + } +} \ No newline at end of file diff --git a/src/contrib/dependencyinjection/Akka.DependencyInjection.Tests/DiPropsSpecs.cs b/src/contrib/dependencyinjection/Akka.DependencyInjection.Tests/DiPropsSpecs.cs new file mode 100644 index 00000000000..9102dd1693c --- /dev/null +++ b/src/contrib/dependencyinjection/Akka.DependencyInjection.Tests/DiPropsSpecs.cs @@ -0,0 +1,73 @@ +// ----------------------------------------------------------------------- +// +// Copyright (C) 2009-2024 Lightbend Inc. +// Copyright (C) 2013-2024 .NET Foundation +// +// ----------------------------------------------------------------------- + +using System; +using System.Threading.Tasks; +using Akka.Actor; +using Akka.Configuration; +using Akka.Dispatch; +using Akka.Util.Internal; +using FluentAssertions; +using Microsoft.Extensions.DependencyInjection; +using Xunit; +using Xunit.Abstractions; + +namespace Akka.DependencyInjection.Tests; + +public class DiPropsSpecs : IAsyncLifetime +{ + private readonly IServiceProvider _serviceProvider; + private readonly AkkaService _akkaService; + private readonly ITestOutputHelper _output; + private TestKit.Xunit2.TestKit _testKit; + + public DiPropsSpecs(ITestOutputHelper output) + { + _output = output; + var services = new ServiceCollection() + .AddSingleton() + .AddSingleton() + .AddHostedService(); + + _serviceProvider = services.BuildServiceProvider(); + _akkaService = _serviceProvider.GetRequiredService(); + } + + + [Fact(DisplayName = "DI should work with custom mailbox")] + public async Task ShouldWorkWithCustomMailbox() + { + var system = _serviceProvider.GetRequiredService().ActorSystem; + var resolver = DependencyResolver.For(system); + const string thing = "foobar"; + var props = resolver.Props(thing).WithMailbox(AkkaService.CustomMailboxName); + var actor = system.ActorOf(props, "testDIActorWithCustomMailbox"); + + var probe = _testKit.CreateTestProbe(system); + actor.Tell(1, probe); + actor.Tell("test", probe); + var result1 = await probe.ExpectMsgAsync(); + result1.Value.Should().Be("I was injected" + thing); + var result2 = await probe.ExpectMsgAsync(); + result2.Value.Should().Be("I was injected" + thing); + + // Verify that the custom mailbox was used + var actorRef = (RepointableActorRef)actor; + actorRef.MailboxType.GetType().Should().Be(typeof(CustomMailbox)); + } + + public async Task InitializeAsync() + { + await _akkaService.StartAsync(default); + _testKit = new TestKit.Xunit2.TestKit(_akkaService.ActorSystem, _output); + } + + public async Task DisposeAsync() + { + await _akkaService.StopAsync(); + } +} \ No newline at end of file diff --git a/src/contrib/dependencyinjection/Akka.DependencyInjection.Tests/RouterIntegrationSpec.cs b/src/contrib/dependencyinjection/Akka.DependencyInjection.Tests/RouterIntegrationSpec.cs index 0e13cd2f559..0a47044e131 100644 --- a/src/contrib/dependencyinjection/Akka.DependencyInjection.Tests/RouterIntegrationSpec.cs +++ b/src/contrib/dependencyinjection/Akka.DependencyInjection.Tests/RouterIntegrationSpec.cs @@ -8,16 +8,12 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Threading; using System.Threading.Tasks; using Akka.Actor; using Akka.Event; using Akka.Routing; -using Akka.TestKit; -using Akka.Util.Internal; using FluentAssertions; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; using Xunit; using Xunit.Abstractions; @@ -131,60 +127,5 @@ public async Task DisposeAsync() { await _akkaService.StopAsync(); } - - internal class TestDiActor : ReceiveActor - { - public static readonly AtomicCounter Counter = new(0); - - public TestDiActor(InjectedService injected) - { - long count = Counter.GetAndIncrement(); - Receive(_ => Sender.Tell(new Message{Value = injected.Message, Counter = count})); - } - } - - internal class Message - { - public string Value { get; set; } - public long Counter { get; set; } - } - - internal class GetMessage - { - public static readonly GetMessage Instance = new(); - private GetMessage() - { } - } - - internal class InjectedService - { - public string Message => "I was injected"; - } - - internal class AkkaService : IHostedService - { - public ActorSystem ActorSystem { get; private set; } - - private readonly IServiceProvider _serviceProvider; - - public AkkaService(IServiceProvider serviceProvider) - { - _serviceProvider = serviceProvider; - } - - public Task StartAsync(CancellationToken cancellationToken) - { - var setup = DependencyResolverSetup.Create(_serviceProvider) - .And(BootstrapSetup.Create().WithConfig(TestKitBase.DefaultConfig)); - - ActorSystem = ActorSystem.Create("TestSystem", setup); - return Task.CompletedTask; - } - - public async Task StopAsync(CancellationToken cancellationToken = default) - { - await ActorSystem.Terminate(); - } - } } } diff --git a/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveCore.DotNet.verified.txt b/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveCore.DotNet.verified.txt index 1835fbc7373..0464eb73ae0 100644 --- a/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveCore.DotNet.verified.txt +++ b/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveCore.DotNet.verified.txt @@ -10,6 +10,7 @@ [assembly: System.Runtime.CompilerServices.InternalsVisibleToAttribute("Akka.Cluster.Tests.MultiNode")] [assembly: System.Runtime.CompilerServices.InternalsVisibleToAttribute("Akka.Cluster.Tools")] [assembly: System.Runtime.CompilerServices.InternalsVisibleToAttribute("Akka.DependencyInjection")] +[assembly: System.Runtime.CompilerServices.InternalsVisibleToAttribute("Akka.DependencyInjection.Tests")] [assembly: System.Runtime.CompilerServices.InternalsVisibleToAttribute("Akka.DistributedData")] [assembly: System.Runtime.CompilerServices.InternalsVisibleToAttribute("Akka.Docs.Tests")] [assembly: System.Runtime.CompilerServices.InternalsVisibleToAttribute("Akka.MultiNodeTestRunner.Shared.Tests")] diff --git a/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveCore.Net.verified.txt b/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveCore.Net.verified.txt index 8739c7aeab9..f0ad7b5459c 100644 --- a/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveCore.Net.verified.txt +++ b/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveCore.Net.verified.txt @@ -10,6 +10,7 @@ [assembly: System.Runtime.CompilerServices.InternalsVisibleToAttribute("Akka.Cluster.Tests.MultiNode")] [assembly: System.Runtime.CompilerServices.InternalsVisibleToAttribute("Akka.Cluster.Tools")] [assembly: System.Runtime.CompilerServices.InternalsVisibleToAttribute("Akka.DependencyInjection")] +[assembly: System.Runtime.CompilerServices.InternalsVisibleToAttribute("Akka.DependencyInjection.Tests")] [assembly: System.Runtime.CompilerServices.InternalsVisibleToAttribute("Akka.DistributedData")] [assembly: System.Runtime.CompilerServices.InternalsVisibleToAttribute("Akka.Docs.Tests")] [assembly: System.Runtime.CompilerServices.InternalsVisibleToAttribute("Akka.MultiNodeTestRunner.Shared.Tests")] diff --git a/src/core/Akka.Remote/EndpointManager.cs b/src/core/Akka.Remote/EndpointManager.cs index 4f101998288..fbd8704708e 100644 --- a/src/core/Akka.Remote/EndpointManager.cs +++ b/src/core/Akka.Remote/EndpointManager.cs @@ -515,10 +515,9 @@ private ICancelable PruneTimerCancelleable private void HandleStashedInbound(IActorRef endpoint, bool writerIsIdle) { - var stashed = _stashedInbound.GetOrElse(endpoint, new List()); - _stashedInbound.Remove(endpoint); - foreach (var ia in stashed) - HandleInboundAssociation(ia, writerIsIdle); + if (_stashedInbound.Remove(endpoint, out var value)) + foreach (var ia in value) + HandleInboundAssociation(ia, writerIsIdle); } private void KeepQuarantinedOr(Address remoteAddress, Action body) diff --git a/src/core/Akka/Properties/AssemblyInfo.cs b/src/core/Akka/Properties/AssemblyInfo.cs index 65294fecdc0..cef4ff40397 100644 --- a/src/core/Akka/Properties/AssemblyInfo.cs +++ b/src/core/Akka/Properties/AssemblyInfo.cs @@ -53,3 +53,4 @@ [assembly: InternalsVisibleTo("Akka.Persistence.TCK")] [assembly: InternalsVisibleTo("Akka.DistributedData")] [assembly: InternalsVisibleTo("Akka.DependencyInjection")] +[assembly: InternalsVisibleTo("Akka.DependencyInjection.Tests")]