Skip to content

Commit

Permalink
Add MAUI support (#293)
Browse files Browse the repository at this point in the history
* Add MAUI support

* work-arounds for MAUI support

* added async startup

* added dedicated Akka.Maui.Hosting library

* getting app to launch correctly now

* fix compilation and namespace errors

* fixed solution rebase

* updating build system to install MAUI workloads

* Revert "updating build system to install MAUI workloads"

This reverts commit 0f8e2ea.

* moving MAUI code to its own solution

* added API approvals

---------

Co-authored-by: Aaron Stannard <aaron@petabridge.com>
  • Loading branch information
Arkatufus and Aaronontheweb committed May 17, 2023
1 parent c57287f commit 92708e7
Show file tree
Hide file tree
Showing 8 changed files with 55 additions and 141 deletions.
38 changes: 19 additions & 19 deletions Akka.Hosting.sln
Original file line number Diff line number Diff line change
Expand Up @@ -13,34 +13,34 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "_build", "build\_build.cspr
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{2B9D74C1-4148-46EF-B3FE-7357839FAF40}"
ProjectSection(SolutionItems) = preProject
src\Directory.Build.props = src\Directory.Build.props
README.md = README.md
RELEASE_NOTES.md = RELEASE_NOTES.md
src\Directory.Build.props = src\Directory.Build.props
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Akka.Hosting.SimpleDemo", "src\Examples\Akka.Hosting.SimpleDemo\Akka.Hosting.SimpleDemo.csproj", "{5F6A7BE8-6906-46CE-BA1C-72EA11EFA33B}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Akka.Hosting.SimpleDemo", "src\Examples\Akka.Hosting.SimpleDemo\Akka.Hosting.SimpleDemo.csproj", "{5F6A7BE8-6906-46CE-BA1C-72EA11EFA33B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Akka.Remote.Hosting", "src\Akka.Remote.Hosting\Akka.Remote.Hosting.csproj", "{AB312E80-5604-44DC-85CD-DF084E5342AE}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Akka.Remote.Hosting", "src\Akka.Remote.Hosting\Akka.Remote.Hosting.csproj", "{AB312E80-5604-44DC-85CD-DF084E5342AE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Akka.Cluster.Hosting", "src\Akka.Cluster.Hosting\Akka.Cluster.Hosting.csproj", "{24436A00-7BAC-4965-9E86-EA8D40AE6AE2}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Akka.Cluster.Hosting", "src\Akka.Cluster.Hosting\Akka.Cluster.Hosting.csproj", "{24436A00-7BAC-4965-9E86-EA8D40AE6AE2}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Examples", "Examples", "{EFA970FF-6BCC-4C38-84D8-324D40F2BF03}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Akka.Remote.Hosting.Tests", "src\Akka.Remote.Hosting.Tests\Akka.Remote.Hosting.Tests.csproj", "{4D748F16-AC22-4E8B-94D7-3DAF6B7CBD00}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Akka.Cluster.Hosting.Tests", "src\Akka.Cluster.Hosting.Tests\Akka.Cluster.Hosting.Tests.csproj", "{EEFCC5A9-94BB-41DA-A9D3-12ACB889FE42}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Akka.Cluster.Hosting.Tests", "src\Akka.Cluster.Hosting.Tests\Akka.Cluster.Hosting.Tests.csproj", "{EEFCC5A9-94BB-41DA-A9D3-12ACB889FE42}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Akka.Persistence.Hosting", "src\Akka.Persistence.Hosting\Akka.Persistence.Hosting.csproj", "{424A63E4-2B7A-45B9-9E69-185277EBE507}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Akka.Persistence.Hosting", "src\Akka.Persistence.Hosting\Akka.Persistence.Hosting.csproj", "{424A63E4-2B7A-45B9-9E69-185277EBE507}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Akka.Persistence.Hosting.Tests", "src\Akka.Persistence.Hosting.Tests\Akka.Persistence.Hosting.Tests.csproj", "{876DE0B6-5FA8-4F79-876E-92EF5E9E7011}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Akka.Persistence.Hosting.Tests", "src\Akka.Persistence.Hosting.Tests\Akka.Persistence.Hosting.Tests.csproj", "{876DE0B6-5FA8-4F79-876E-92EF5E9E7011}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Akka.Hosting.LoggingDemo", "src\Examples\Akka.Hosting.LoggingDemo\Akka.Hosting.LoggingDemo.csproj", "{4F79325B-9EE7-4501-800F-7A1F8DFBCC80}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Akka.Hosting.LoggingDemo", "src\Examples\Akka.Hosting.LoggingDemo\Akka.Hosting.LoggingDemo.csproj", "{4F79325B-9EE7-4501-800F-7A1F8DFBCC80}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Akka.Hosting.TestKit", "src\Akka.Hosting.TestKit\Akka.Hosting.TestKit.csproj", "{E28D4F3C-6C34-497B-BDC8-F2B3EA8BA309}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Akka.Hosting.TestKit", "src\Akka.Hosting.TestKit\Akka.Hosting.TestKit.csproj", "{E28D4F3C-6C34-497B-BDC8-F2B3EA8BA309}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Akka.Hosting.TestKit.Tests", "src\Akka.Hosting.TestKit.Tests\Akka.Hosting.TestKit.Tests.csproj", "{3883AD08-B981-4943-8153-1E7FFD2C3127}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Akka.Hosting.TestKit.Tests", "src\Akka.Hosting.TestKit.Tests\Akka.Hosting.TestKit.Tests.csproj", "{3883AD08-B981-4943-8153-1E7FFD2C3127}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Akka.Hosting.API.Tests", "src\Akka.Hosting.API.Tests\Akka.Hosting.API.Tests.csproj", "{410065E0-6636-4F34-85AE-4C4BA413ADB4}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Akka.Hosting.API.Tests", "src\Akka.Hosting.API.Tests\Akka.Hosting.API.Tests.csproj", "{410065E0-6636-4F34-85AE-4C4BA413ADB4}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Akka.Remote.Hosting.Tests", "src\Akka.Remote.Hosting.Tests\Akka.Remote.Hosting.Tests.csproj", "{11062839-0674-4DF9-AB8B-B7901A564ADC}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down Expand Up @@ -74,10 +74,6 @@ Global
{24436A00-7BAC-4965-9E86-EA8D40AE6AE2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{24436A00-7BAC-4965-9E86-EA8D40AE6AE2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{24436A00-7BAC-4965-9E86-EA8D40AE6AE2}.Release|Any CPU.Build.0 = Release|Any CPU
{4D748F16-AC22-4E8B-94D7-3DAF6B7CBD00}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4D748F16-AC22-4E8B-94D7-3DAF6B7CBD00}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4D748F16-AC22-4E8B-94D7-3DAF6B7CBD00}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4D748F16-AC22-4E8B-94D7-3DAF6B7CBD00}.Release|Any CPU.Build.0 = Release|Any CPU
{EEFCC5A9-94BB-41DA-A9D3-12ACB889FE42}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EEFCC5A9-94BB-41DA-A9D3-12ACB889FE42}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EEFCC5A9-94BB-41DA-A9D3-12ACB889FE42}.Release|Any CPU.ActiveCfg = Release|Any CPU
Expand Down Expand Up @@ -106,15 +102,19 @@ Global
{410065E0-6636-4F34-85AE-4C4BA413ADB4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{410065E0-6636-4F34-85AE-4C4BA413ADB4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{410065E0-6636-4F34-85AE-4C4BA413ADB4}.Release|Any CPU.Build.0 = Release|Any CPU
{11062839-0674-4DF9-AB8B-B7901A564ADC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{11062839-0674-4DF9-AB8B-B7901A564ADC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{11062839-0674-4DF9-AB8B-B7901A564ADC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{11062839-0674-4DF9-AB8B-B7901A564ADC}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {B99E6BB8-642A-4A68-86DF-69567CBA700A}
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{5F6A7BE8-6906-46CE-BA1C-72EA11EFA33B} = {EFA970FF-6BCC-4C38-84D8-324D40F2BF03}
{4F79325B-9EE7-4501-800F-7A1F8DFBCC80} = {EFA970FF-6BCC-4C38-84D8-324D40F2BF03}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {B99E6BB8-642A-4A68-86DF-69567CBA700A}
EndGlobalSection
EndGlobal
2 changes: 1 addition & 1 deletion build/Build.cs
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ private string PreReleaseVersionSuffix()
var releaseNotes = MdHelper.GetNuGetReleaseNotes(ChangelogFile, GitRepository);
var versionSuffix = VersionSuffix;
var projects = SourceDirectory.GlobFiles("**/*.csproj")
.Except(SourceDirectory.GlobFiles("**/*Tests.csproj", "**/*Tests*.csproj", "**/*Demo.csproj"));
.Except(SourceDirectory.GlobFiles("**/*Tests.csproj", "**/*Tests*.csproj", "**/*Demo.csproj", "**/*Sample.csproj"));
foreach (var project in projects)
{
DotNetPack(s => s
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Akka.Hosting.Tests")]
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Akka.Hosting.Maui")]
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Akka.Hosting.Tests")]
namespace Akka.Hosting
{
public class ActorRegistry : Akka.Actor.IExtension, Akka.Hosting.IActorRegistry, Akka.Hosting.IReadOnlyActorRegistry, System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<System.Type, Akka.Actor.IActorRef>>, System.Collections.IEnumerable
Expand Down
8 changes: 4 additions & 4 deletions src/Akka.Hosting/AkkaHostedService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ internal sealed class AkkaHostedService : IHostedService
private CoordinatedShutdown? _coordinatedShutdown; // grab a reference to CoordinatedShutdown early
private readonly IServiceProvider _serviceProvider;
private readonly AkkaConfigurationBuilder _configurationBuilder;
private readonly IHostApplicationLifetime _hostApplicationLifetime;
private readonly IHostApplicationLifetime? _hostApplicationLifetime;
private readonly ILogger<AkkaHostedService> _logger;

public AkkaHostedService(AkkaConfigurationBuilder configurationBuilder, IServiceProvider serviceProvider,
ILogger<AkkaHostedService> logger, IHostApplicationLifetime applicationLifetime)
ILogger<AkkaHostedService> logger, IHostApplicationLifetime? applicationLifetime)
{
_configurationBuilder = configurationBuilder;
_hostApplicationLifetime = applicationLifetime;
Expand All @@ -40,7 +40,7 @@ public async Task StartAsync(CancellationToken cancellationToken)
async Task TerminationHook()
{
await _actorSystem.WhenTerminated.ConfigureAwait(false);
_hostApplicationLifetime.StopApplication();
_hostApplicationLifetime?.StopApplication();
}

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

Expand Down
15 changes: 12 additions & 3 deletions src/Akka.Hosting/AkkaHostingExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
using Akka.Configuration;
using Akka.DependencyInjection;
using Akka.Hosting.Configuration;
using Akka.Util;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
Expand Down Expand Up @@ -63,8 +62,18 @@ public static IServiceCollection AddAkka(this IServiceCollection services, strin
// registers the hosted services and begins execution
b.Bind();

// start the IHostedService which will run Akka.NET
services.AddHostedService<AkkaHostedService>();
if (Util.IsRunningInMaui)
{
// blow up Maui users who are about to footgun
throw new PlatformNotSupportedException(
"Due to https://github.com/dotnet/maui/issues/2244, normal Akka.Hosting.AddAkka method will not work." +
"Instead, you need to install Akka.Hosting.Maui and use the AddAkkaMaui extension method instead.");
}
else
{
// start the IHostedService which will run Akka.NET
services.AddHostedService<AkkaHostedService>();
}

return services;
}
Expand Down
3 changes: 2 additions & 1 deletion src/Akka.Hosting/Properties/FriendsOf.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Runtime.CompilerServices;

[assembly: InternalsVisibleTo("Akka.Hosting.Tests")]
[assembly: InternalsVisibleTo("Akka.Hosting.Tests")]
[assembly: InternalsVisibleTo("Akka.Hosting.Maui")]
12 changes: 12 additions & 0 deletions src/Akka.Hosting/Util.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
// </copyright>
// -----------------------------------------------------------------------

using System;
using System.Linq;
using Akka.Configuration;
using Akka.Configuration.Hocon;
Expand All @@ -14,6 +15,17 @@ namespace Akka.Hosting
{
public static class Util
{
// HACK: MAUI runtime detection
private static bool? _runningInMaui;
internal static bool IsRunningInMaui
{
get
{
_runningInMaui ??= AppDomain.CurrentDomain.GetAssemblies().Any(asm => asm.GetName().Name.StartsWith("Microsoft.Maui"));
return _runningInMaui.Value;
}
}

public static Config MoveTo(this Config config, string path)
{
var rootObj = new HoconObject();
Expand Down
115 changes: 3 additions & 112 deletions src/Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,118 +1,9 @@
<Project>
<Project>
<PropertyGroup>
<Copyright>Copyright © 2013-2023 Akka.NET Team</Copyright>
<Authors>Akka.NET Team</Authors>
<VersionPrefix>1.5.0-beta4</VersionPrefix>
<PackageReleaseNotes><![CDATA[Version 1.5.0-beta4 integrates Akka.NET v1.5 into Akka.Hosting
• [Update Akka.NET to 1.5.0-beta4](https://github.com/akkadotnet/akka.net/releases/tag/1.5.0-beta4)
#### Upgrading From v1.4 To v1.5
As noted in [the upgrade advisories](https://github.com/akkadotnet/akka.net/blob/c9ccc25207b5a4cfa963a5a23f96c0676fbbef10/docs/community/whats-new/akkadotnet-v1.5-upgrade-advisories.md)%2C there was a major change in Akka.Cluster.Sharding state storage. These notes contains the same documentation%2C but tailored for Akka.Hosting users
The recommended settings for maximum ease-of-use for Akka.Cluster.Sharding in new applications going forward will be:
csharp
var options = new ShardOptions
{
StateStoreMode = StateStoreMode.DData%2C
RememberEntitiesStore = RememberEntitiesStore.Eventsourced
}%3B
You will need to set these options manually because the default settings are set for backward compatibility.
#### Migrating to New Sharding Storage From Akka.Persistence
> **NOTE**
>
> This section applies only to users who were using StateStoreMode = StateStoreMode.Persistence.
Switching over to using RememberEntitiesStore = RememberEntitiesStore.Eventsourced will cause an initial migration of data from the ShardCoordinator's journal into separate event journals going forward.
Upgrading to Akka.NET v1.5 will **cause an irreversible migration of Akka.Cluster.Sharding data*• for users who were previously running StateStoreMode = StateStoreMode.Persistence%2C so follow the steps below carefully:
##### Step 1 • Upgrade to Akka.NET v1.5 With New Options Setup
Update your Akka.Cluster.Sharding options to look like the following (adjust as necessary for your custom settings):
csharp
hostBuilder.Services.AddAkka("MyActorSystem"%2C builder =>
{
var shardOptions = new ShardOptions
{
// If you don't run Akka.Cluster.Sharding with RememberEntities = true%2C
// then set this to false
RememberEntities = true%2C
RememberEntitiesStore = RememberEntitiesStore.Eventsourced%2C
StateStoreMode = StateStoreMode.Persistence%2C
//fail if upgrade doesn't succeed
FailOnInvalidEntityStateTransition = true
}%3B
// Modify these two options to suit your application%2C SqlServer used
// only as an illustration
var journalOptions = new SqlServerJournalOptions()%3B
var snapshotOptions = new SqlServerSnapshotOptions()%3B
builder
.WithClustering()
.WithSqlServerPersistence(journalOptions%2C snapshotOptions)
.WithShardRegion<UserActionsEntity>(
"userActions"%2C
s => UserActionsEntity.Props(s)%2C
new UserMessageExtractor()%2C
// shardOptions is being used here
shardOptions)%3B
// Add the Akka.Cluster.Sharding migration journal event adapter
builder.WithClusterShardingJournalMigrationAdapter(journalOptions)%3B
// you can also declare the adapter by referencing the journal ID directly
builder.WithClusterShardingJournalMigrationAdapter("akka.persistence.journal.sql-server")%3B
})
With these HOCON settings in-place the following will happen:
1. The old PersitentShardCoordinator state will be broken up • Remember entities data will be distributed to each of the PersistentShard actors%2C who will now use the new RememberEntitiesStore = RememberEntitiesStore.Eventsourced setting going forward%3B
2. Old Akka.Cluster.Sharding.ShardCoordinator.IDomainEvent events will be upgraded to a new storage format via the injected Akka.Persistence event adapter%3B and
3. The PersistentShardCoordinator will migrate its journal to the new format as well.
##### Step 2 • Migrating Away From Persistence to DData
Once your cluster has successfully booted up with these settings%2C you can now optionally move to using distributed data to store sharding state by changing StateStoreMode = StateStoreMode.DData and deploying a second time:
csharp
hostBuilder.Services.AddAkka("MyActorSystem"%2C builder =>
{
var shardOptions = new ShardOptions
{
RememberEntities = true%2C
RememberEntitiesStore = RememberEntitiesStore.Eventsourced%2C
// Change this line of code
StateStoreMode = StateStoreMode.DData%2C
FailOnInvalidEntityStateTransition = true
}%3B
var journalOptions = new SqlServerJournalOptions()%3B
var snapshotOptions = new SqlServerSnapshotOptions()%3B
builder
.WithClustering()
.WithSqlServerPersistence(journalOptions%2C snapshotOptions)
.WithShardRegion<UserActionsEntity>(
"userActions"%2C
s => UserActionsEntity.Props(s)%2C
new UserMessageExtractor()%2C
shardOptions)%3B
builder.WithClusterShardingJournalMigrationAdapter(journalOptions)%3B
})
Now you'll be running Akka.Cluster.Sharding with the recommended settings.
#### Migrating to New Sharding Storage From Akka.DistributedData
The migration process onto Akka.NET v1.5's new Cluster.Sharding storage system is less involved for users who were already using StateStoreMode = StateStoreMode.DData. All these users need to do is change the RememberEntitiesStore option to RememberEntitiesStore.Eventsourced
csharp
hostBuilder.Services.AddAkka("MyActorSystem"%2C builder =>
{
var shardOptions = new ShardOptions
{
RememberEntities = true%2C
// Use this option setting
RememberEntitiesStore = RememberEntitiesStore.Eventsourced%2C
StateStoreMode = StateStoreMode.DData%2C
FailOnInvalidEntityStateTransition = true
}%3B
var journalOptions = new SqlServerJournalOptions()%3B
var snapshotOptions = new SqlServerSnapshotOptions()%3B
builder
.WithClustering()
.WithSqlServerPersistence(journalOptions%2C snapshotOptions)
.WithShardRegion<UserActionsEntity>(
"userActions"%2C
s => UserActionsEntity.Props(s)%2C
new UserMessageExtractor()%2C
shardOptions)%3B
builder.WithClusterShardingJournalMigrationAdapter(journalOptions)%3B
})
]]></PackageReleaseNotes>
<VersionPrefix>1.5.6</VersionPrefix>
<PackageReleaseNotes>• [Update Akka.NET to 1.5.6](https://github.com/akkadotnet/akka.net/releases/tag/1.5.6)</PackageReleaseNotes>
<PackageIcon>akkalogo.png</PackageIcon>
<PackageProjectUrl>
https://github.com/akkadotnet/Akka.Hosting
Expand Down

0 comments on commit 92708e7

Please sign in to comment.