akkadotnet / akka.net

Canonical actor model implementation for .NET with local + distributed actors in C# and F#.
http://getakka.net
Other
4.7k stars 1.04k forks source link

Should we adopt Microsoft.Extensions libraries? #3050

Closed Horusiath closed 2 years ago

Horusiath commented 7 years ago

This is only an idea, but maybe it's worth discussing. At the present moment we can see, that there are several libraries (by convention called Microsoft.Extensions.*.Abstractions), that are meant to provide a .NET Standard wide API for common things like caching, configuration, logging or dependency injection.

We already were loosely talking about potential to improve some parts of the Akka.NET API. I'm not talking about supporting all of them or none, but at least some of those would give us potential gain. Want to hear your thoughts @akkadotnet/core .

1. Abstracting HOCON configuration into objects

Most (all?) of the current akka extensions are already parsing HOCON config directly into object notation. The idea was to get rid of the direct HOCON dependencies in the internals, relying totally on objects instead.

This is place where Microsoft.Extensions.Configuration.* libraries would be handy: they provide common abstractions like IConfiguration, IConfigurationSource, ConfigurationPath etc. Moreover there are already implementations that automatically will allow us to parse i.e. Json, Xml or even Command Line arguments into that notation.

We'd need to do several things:

Pros:

2. Abstracting actor creation pipeline

As I've already proposed (#1675) and PRed (#2638) , we could replace current complex actor creation pipeline and abstract it together with dependency injection plugins. Some of the MS frameworks, like Orleans and ASP.NET Core, are already using Microsoft.Extensions.DependencyInjection.* libraries to provide a generic construction mechanism. We could adopt it on our side as well.

Pros:

3. Abstracting logging libraries

Microsoft.Extensions.Logging,* libaries give us primitives to abstract logging capability. This way we could outsource concrete implementations (NLog, log4net, Serilog) outside. However looking at nuget this is the most messy case of all.

Pros:

Danthar commented 7 years ago

My thoughts on this:

1: Abstracting HOCON configuration into objects

I am all for extracting the current version of Hocon from the akka.net core codebase. And bringing the existing separate Hocon repo up to date. And then having the core codebase depend on that instead. (I would refer to this as: "the initial legwork")

After that we can probably create a Microsoft.Extensions.Configuration.Hocon implementation. I am not sure about the IDE support though. I don't see how creating an implementation for Microsoft.Extensions.Configuration would magically give Hocon IDE support. And by that I am talking about something more then just raw string editing. One could argue that configuring VS to treat Hocon files as JSON works just as well at the moment.

2. Abstracting actor creation pipeline

+1 on this. With a side remark that as of 1.3 we only officially support Autofac as a DI container.

3. Abstracting logging libraries

This is perhaps the most tricky one yet. But having a default logger which looks to the Microsoft.Extensions.Logging stuff to do the actual logging would make logging plugins virtually obsolete.

Aaronontheweb commented 7 years ago

Any of the above must come with a migration path for current users.

BlueManiac commented 6 years ago

Has any work been done on better integration with Microsoft.Extensions.Logging? It's quite the hazzle to set it up right now as you can't seem to be able pass a logger instance to akka directly currently. Passing parameters do not seem to be possible either.

Horusiath commented 6 years ago

@BlueManiac you can set your own logger and pass it using HOCON configuration:

akka.loggers = [ "MyNamespace.MyLogger, MyAssembly" ]
BlueManiac commented 6 years ago

@Horusiath Yes, I know, i'm currently using the serilog logger adapter there. I would like to pass a custom logger there instead that isn't passed in some static variable somewhere that you seem to be required to use right now. (the serilog akka logger uses serilog's static Log.Logger property)

pshrosbree commented 6 years ago

I'd advise against using Microsoft.Extensions.DependencyInjection. It is an implementation of the Conforming Container anti-pattern. Mark Seeman wrote about Microsoft.Extensions.DependencyInjection in Feedback on ASP.NET vNext Dependency Injection. While this is an old article, it is clear from pre-releases of his Dependency Injection in .NET, Second Edition that nothing in more recent releases has changed his views on this.

I agree with this position.

beachwalker commented 4 years ago

I'm more interested in using IConfiguration.

I'd advise against using Microsoft.Extensions.DependencyInjection. It is an implementation of the Conforming Container anti-pattern. Mark Seeman wrote about Microsoft.Extensions.DependencyInjection in Feedback on ASP.NET vNext Dependency Injection. While this is an old article, it is clear from pre-releases of his Dependency Injection in .NET, Second Edition that nothing in more recent releases has changed his views on this.

I agree with this position.

I do not agree with all of the points mentioned there. Also this left the point of code sharing capabilities, for example think about the Add* extensions available for ASP.net core. For me, Autofac integrates well with the ServiceCollections provided by the DI Extensions. The interface already proved well and not the interface ist responsible for protecting from applying bad patterns around it. So you can go to dark side with specific containers, too.

And there is more than DI. I would like to see integration with Microsoft.Extensions.Configuration. And this is not an all or nothing.

dgioulakis commented 4 years ago

Mark Seeman has some fantastic articles and I've followed his work for years. A number of points in that specific article still hold true today. What doesn't ring true are his conclusions. DI has come a long way over the past 10 years. It's so paramount to extensible design that it's even now in practice in front-end javascript frameworks and functional paradigms.

The reality is, whether Mr. Seeman likes it or not, there is a common, stable intersection of baseline functionality that a DI container must be capable of. The community has helped shape this over the many revisions of frameworks. Microsoft.Extensions.DependencyInjection is not new ... it's been kicked around and refactored a hundred times over in various incarnations and names - taking best practices from the community.

Akka.net should absolutely adopt this going forward. The unification towards a generic host and these various extension addons has made dotnet core development a great experience. IMO

Aaronontheweb commented 4 years ago

The more I think about it, I think there might be some value in porting something similar to ActorSystemStartup.

Directly supporting DI inside actors - probably not something we're going to do. Introduces unpredictably expensive third party components into an extremely concurrent area of the system for minimal value. Pass in a reference to the IServiceCollection into your actor's constructor and don't ask us to lard up the guts of the framework for a use case that isn't common and not that hard to solve in user code.

Passing in DI and IConfiguration for enabling settings like tracing, serialization, and so on - yeah I could see that. The configuration hit for all of those items occurs exactly once at ActorSystem creation and that's it. Due to the concurrent nature of actors we'd never support something like configuration reloading - realistically you have to restart the ActorSystem to do that.

martinmine commented 2 years ago

It would be really great if Akka.net would adopt these libraries. The way I have to load up a HOCON-file using File.ReadAllText today feels weird opposed to how modern .NET libraries/frameworks approaches configuration. From a modern .NET framework I have a certain expectation that I should be able to use ILogger, IServiceCollection, and IConfiguration. These are interfaces that are well adopted across various .NET ecosystems and at this point I wouldn't even say there is much controversy around them. There has been great progress on how DI is handled, now the rest remains.

Aaronontheweb commented 2 years ago

So where's what we ultimately want to do with the project - make it easier to configure Akka.NET and integrate it into the other technologies .NET developers use.

We'll never take a direct dependency on IConfiguration, for instance, because the Microsoft.Extensions.* model for configuration doesn't align with what Akka.NET needs (i.e. read-performance, overrides, immutability) and will lead to a lot of problems down the road. However, we can certainly want to make it easier to consume values from IConfiguration and inject them into the HOCON an ActorSystem uses at startup.

From a modern .NET framework I have a certain expectation that I should be able to use ILogger, IServiceCollection, and IConfiguration

We have plans to support all of them, ILogger probably being next: https://github.com/akkadotnet/akka.net/issues/4937 - you're still going to want to call ILoggingAdapter inside your actors (because this safely decouples the logging pipeline from all actor message processing), but that output will all be safely piped out to the ILogger.

As for IConfiguration, that's included in the HOCON 3.0 specification https://github.com/akkadotnet/HOCON/issues/267

Aaronontheweb commented 2 years ago

Some updates: Akka.Hosting and Akka.DependencyInjection basically complete this issue:

So with all that being said, I think we've accomplished this primarily through Akka.Hosting. Feedback on the experience from end-users has been great so far and I actually like the Akka.Hosting's release lifecycle is decoupled from Akka.NET itself as it makes it cheaper for us to do more frequent releases.

Aaronontheweb commented 2 years ago

The way I have to load up a HOCON-file using File.ReadAllText today feels weird opposed to how modern .NET libraries/frameworks approaches configuration.

This is an example of something we've tackled in Akka.Hosting too - you can just do AddHoconFile now and it will pull that configuration in, just like pulling in an appsettings.json file.

We'll keep iterating on these issues on Akka.Hosting - the whole purpose of that library is to simplify Akka.NET configuration and to make it very cheap to build reusable Akka.NET middleware (i.e. writing your own extension methods to configure identical, strongly-typed Akka.Persistence configurations across multiple services, for instance.)

Aaronontheweb commented 2 years ago

Akka.Hosting explained: https://www.youtube.com/watch?v=Mnb9W9ClnB0

martinmine commented 2 years ago

This is really awesome, I think this is a huge step to make Akka.Net a lot easier for newcomers as well, well done @Aaronontheweb!

Aaronontheweb commented 2 years ago

Thanks! The hard part is going to be updating all of the documentation and samples but we're hard at work on that too, i.e. https://github.com/petabridge/akkadotnet-code-samples/issues/94