Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ServiceProviderProps and Props Changes #4858

Merged
merged 13 commits into from Mar 18, 2021

Conversation

Aaronontheweb
Copy link
Member

close #4853
close #3599

API approvals and ServiceProviderProps changes aren't done yet - just wanted to kick off the test suite to make sure I haven't massively blown it on introducing these changes safely.

@Aaronontheweb Aaronontheweb changed the title [WIP] ServiceProviderProps and Props Changes ServiceProviderProps and Props Changes Mar 17, 2021
@Aaronontheweb Aaronontheweb marked this pull request as ready for review March 17, 2021 16:54
@Aaronontheweb
Copy link
Member Author

Should be good to go now.

@Aaronontheweb
Copy link
Member Author

Looks like these changes blew up Akka.Cluster.Sharding....

Copy link
Member Author

@Aaronontheweb Aaronontheweb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Described my changes in this PR

///// <typeparam name="T">The type of actor to instantiate.</typeparam>
///// <param name="producer">The delegate used to create a new instance of your actor type.</param>
///// <returns>A new <see cref="Props"/> instance which uses DI internally.</returns>
//public Props Props<T>(Func<IServiceProvider, T> producer) where T : ActorBase
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commented out method - just removed it.

@@ -74,7 +59,7 @@ public static ServiceProvider For(ActorSystem actorSystem)
/// <returns>A new <see cref="Akka.Actor.Props"/> instance which uses DI internally.</returns>
public Props Props<T>(params object[] args) where T : ActorBase
{
return new ServiceProviderProps<T>(Provider, args);
return Akka.Actor.Props.CreateBy(new ServiceProviderActorProducer<T>(Provider, args));
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use the new Props.CreateBy method with takes an IIndirectActorProducer reference directly.

/// <typeparam name="TActor">The type of the actor to create.</typeparam>
internal class ServiceProviderProps<TActor> : Props where TActor : ActorBase
/// <typeparam name="TActor">the actor type</typeparam>
internal sealed class ServiceProviderActorProducer<TActor> : IIndirectActorProducer where TActor:ActorBase
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactor the ServiceProviderProps into an IIndirectActorProducer that can be used directly inside the Props class.

{
return new ServiceProviderProps<TActor>(_provider, Arguments)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no-op for this class - scopes are meant to be managed directly by the users.

@@ -1408,8 +1408,11 @@ namespace Akka.Actor
public static Akka.Actor.Props Create<TActor>(Akka.Actor.SupervisorStrategy supervisorStrategy)
where TActor : Akka.Actor.ActorBase, new () { }
public static Akka.Actor.Props Create(System.Type type, params object[] args) { }
[System.ObsoleteAttribute("Do not use this method. Call CreateBy(IIndirectActorProducer, params object[] arg" +
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All public API changes made to the Props class - kept it to a bare minimum for compatibility reasons.

/// </summary>
/// <typeparam name="TActor">The type of the actor to create.</typeparam>
/// <param name="args">The arguments needed to create the actor.</param>
/// <returns>The newly created <see cref="Akka.Actor.Props" />.</returns>
public static Props Create<TActor>(params object[] args) where TActor : ActorBase
{
return new Props(typeof(TActor), args);
return new Props(new ActivatorProducer(typeof(TActor), args), DefaultDeploy, args);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use the ActivatorProducer directly, rather than use reflection to create it.

/// </summary>
/// <typeparam name="TProducer">The type of producer used to create the actor.</typeparam>
/// <param name="args">The arguments needed to create the actor.</param>
/// <returns>The newly created <see cref="Akka.Actor.Props" />.</returns>
[Obsolete("Do not use this method. Call CreateBy(IIndirectActorProducer, params object[] args) instead")]
public static Props CreateBy<TProducer>(params object[] args) where TProducer : class, IIndirectActorProducer
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method sucks - marked as Obsolete.

/// <param name="producer">The actor producer that will be used to create the underlying actor..</param>
/// <param name="args">The arguments needed to create the actor.</param>
/// <returns>The newly created <see cref="Akka.Actor.Props" />.</returns>
public static Props CreateBy(IIndirectActorProducer producer, params object[] args)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Take an explicit IIndirectActorProducer - the ServiceProvider extension now calls this method directly.

/// <returns>The newly created <see cref="Akka.Actor.Props" />.</returns>
public static Props CreateBy(IIndirectActorProducer producer, params object[] args)
{
return new Props(producer, DefaultDeploy, args);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

even though the args presumably get passed intro the IIndirectActorProducer, we still have to pass them into the Props constructor because they're used for things like remote deployments.

}

[Obsolete("we should not be calling this method. Pass in an explicit IIndirectActorProducer reference isntead.")]
private static IIndirectActorProducer CreateProducer(Type type, object[] args)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Source of most of the weirdness I identified in #3599 stem from this method, which conflates accepting a Type for an actor with a Type for an IIndirectActorProducer, which has the effect of making it really difficult to reason about what is happening internally and performing reflection twice for all actor invocations.

@Aaronontheweb
Copy link
Member Author

I think I have the test suite under control now - going to run some benchmarks next.

@Aaronontheweb
Copy link
Member Author

With this PR:

Method Mean Error StdDev Gen 0 Gen 1 Gen 2 Allocated
Actor_spawn 23.75 us 1.253 us 0.829 us 1.5700 0.3400 - 9.31 KB

Dev:

Method Mean Error StdDev Gen 0 Gen 1 Gen 2 Allocated
Actor_spawn 24.10 us 1.209 us 0.799 us 1.5600 0.3400 - 9.31 KB

Looks like we got a small improvement by stripping out some of the extra reflection.

@Aaronontheweb
Copy link
Member Author

Eh, performance difference looks about the same actually - probably no negative or positive impact from this change.

Copy link
Contributor

@Arkatufus Arkatufus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@Arkatufus Arkatufus enabled auto-merge (squash) March 17, 2021 21:15
@Arkatufus Arkatufus merged commit d2b8875 into akkadotnet:dev Mar 18, 2021
@Aaronontheweb Aaronontheweb deleted the fix/4853-ServiceProviderProps branch March 18, 2021 01:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
2 participants