dotnet / orleans

Cloud Native application framework for .NET
https://docs.microsoft.com/dotnet/orleans
MIT License
10.15k stars 2.04k forks source link

Multiple clients in one servicecollention #8469

Open spingee opened 1 year ago

spingee commented 1 year ago

Hello, Is it possible to define multiple clients for differnet clusters in one appdomain/servicecolletion. Or another usecase we have localhost/inmemory orleans defined on IHost but want connect to real cluster with different client. Is this possible? Thanks for answer

orionstudt commented 1 year ago

Bumping because I would also like to know if this functionality is currently possible. In v3 it was possible doing something like this library but I haven't figured out a way to do it in v7 since we no longer have access to IClientBuilder.Build().

orionstudt commented 1 year ago

Ok I found this response which claims that it's doable by having multiple hosts.

It also claims it's easier? Not sure how that would be the case now that you have to manage separate host lifetimes and separate service collections.

ReubenBond commented 1 year ago

You don't necessarily need multiple hosts, but you do need multiple ServiceCollections, one per client, and you would need to plumb the cross-cutting concerns (ILoggerFactory, the ILogger<> registration, etc) from the host to the client container, and then you'd need to register an IHostedService in the host container to start the IHostedService registered by the client.

I think an update to Orleans.MultiClient is the right approach, to essentially implement what I mentioned. In .NET 8, we will have Keyed DI in .NET itself, so it's possible that you could register the relevant IClusterClient and IGrainFactory instances with the host container that way.

orionstudt commented 1 year ago

Right, when I said hosts I guess I meant multiple IHosts.

Is there a functional reason why this is an unsupported configuration? Does Orleans recommend against consuming multiple clusters?

Since with the v7 changes it seems like a design decision away from a configuration that was more possible previously when we had more control over ClientBuilder.

ReubenBond commented 1 year ago

The old approach was just doing this anyway: the ClientBuilder was effectively a HostBuilder, creating/destroying its own container and starting a hosted service. It was confusing for people. The new approach is that you have a host (since you would have a host anyway for the vast majority of apps) and you add the client bits to it - no separate containers, no separate logging configuration, IConfiguration, no separate lifecycle management, etc.

The downside of this otherwise easier approach is that it's not as obvious how to create multiple clients in a single app. Creating multiple HostBuilders is very close to creating multiple ClientBuilders, even if it feels heavier. You have more control now, using the de-bundled approach.

All of this being said, we are open to the idea of having standalone clients or clients registered using Keyed DI (using the technique I mentioned above of referencing shared services across containers). This scenario seems common enough that having in-built support for it could be worthwhile.

orionstudt commented 1 year ago

@ReubenBond That makes sense. It does seem heavier just because as the consumer we're doing more work than we were before but I can see how that is simpler on your end and we get more flexibility overall.

I'm working on an implementation that does just that now - and one thing I'm missing is IClusterClient.Connect() - is that not necessary anymore?

Here in the documentation it looks like both the v7 and v3 docs are referring to the old client builder when talking about a hosted service that handles connecting and closing.

SoucianceEqdamRashti commented 1 year ago

@ReubenBond , is there anywhere we can get a sample of what the recommended approach is for creating clients? Especially external clients? The documentation mentions various ways but I think it would be good if the client portion had more details and a clear sample code. Especially for external clients as that is the more complicated one.

jsukhabut commented 7 months ago

Is there any planned worked to use Keyed DI to support multiple clients?

MickaelThumerel commented 5 months ago

@SoucianceEqdamRashti ClusterClient the internal Implementation of IClusterClient implement also IHostedService used to start and stop. So try to get IClusterCLient and try to cast it to IHostedService

AntonPetrov83 commented 3 months ago

We were migrating from 3.x to Orleans 8 and I faced this problem too 😞 Just if anyone is interested we used a frontend cluster talking to several backend clusters (silos). They are separate clusters because we deploy them independently and basically they are different versions of our app. So different versions of mobile clients were eventually talking to different backend clusters. This allowed smooth client releases and upgrades among different platforms.

ReubenBond commented 3 months ago

We should make this easier... an add-on could achieve this with one DI container per client, and keyed DI to map the client back into the parent container. For example, it could work like so:

Would that fit the use cases here? This would not enable the creation of new clients at runtime but allows them to all be attached to a single host. If the creation of new clients at runtime is required, then that can be achieved with more effort, without the use of keyed DI. If there is a proposal for how people would like this to look & work, that would be very helpful

AntonPetrov83 commented 3 months ago

Yes we need creating clients in runtime. And our clustering configuration can change in runtime too, new cluster added, some old cluster removed etc. This makes implementation even harder because of client's lifetime control issues 😬