Interceptors chain for receive
I'm playing around with the new aroundReceive, as you guys suggested me some days ago, to implement the contextual actors pattern.
And after using it for a while, I have some feedback. I think it is needed a way to wrap/decorate receive invocation, and aroundReceive could be a good approach for internal use, but I think it won't fit the final users needs, if you have to plugin multiple decorations, overriding mechanism isn't flexible enough. You have not the total control to decide if some decoration will be inner or outer relatively to other.
So, I think that the know interceptors chain pattern could fit perfectly for this purpose. We can have just one trait overriding aroundReceive which has the ability to add interceptors to the chain, and execute them all around receive invocation.
interceptReceive(interceptor) // Adds to chain's end, or start
interceptReceive(interceptor2, order = 2) // honors order (somehow)
interceptReceive(interceptor3, before = classOf[Interceptor2]) // Adds to chain's relatively to existing interceptor
The interceptors could be added by mixin traits that contribute to the chain, a hook could be provided for adding default interceptors and we can also specify interceptos at creation time with something like this:
Props[InterceptedActor].withInterceptors(List(interceptor1, interceptor2))
Tell me what you think, if it worth the try I could spent some time on it and come up we an initial implementation.
If you think it's a bad idea I'll keep thinking :-)
Cheers!
@ktonga
And after using it for a while, I have some feedback. I think it is needed a way to wrap/decorate receive invocation, and aroundReceive could be a good approach for internal use, but I think it won't fit the final users needs, if you have to plugin multiple decorations, overriding mechanism isn't flexible enough. You have not the total control to decide if some decoration will be inner or outer relatively to other.
So, I think that the know interceptors chain pattern could fit perfectly for this purpose. We can have just one trait overriding aroundReceive which has the ability to add interceptors to the chain, and execute them all around receive invocation.
interceptReceive(interceptor) // Adds to chain's end, or start
interceptReceive(interceptor2, order = 2) // honors order (somehow)
interceptReceive(interceptor3, before = classOf[Interceptor2]) // Adds to chain's relatively to existing interceptor
The interceptors could be added by mixin traits that contribute to the chain, a hook could be provided for adding default interceptors and we can also specify interceptos at creation time with something like this:
Props[InterceptedActor].withInterceptors(List(interceptor1, interceptor2))
Tell me what you think, if it worth the try I could spent some time on it and come up we an initial implementation.
If you think it's a bad idea I'll keep thinking :-)
Cheers!
@ktonga
Leave a comment
This sounds very complicated to me: an Actor is just a thing which can react to messages by sending messages, changing behavior and creating more actors. We should not convert it into a ServiceAdapterMetaProxyFactorySingletonProvider ;-)
On the technical level I believe that aroundReceive already allows full control over the order in which things get stacked: the actor definition itself is the place where the order of mixins or superclasses determines this. Can you point out a specific problem that is not solvable with this and which we actually should want to solve at the toolkit level?
Sorry for maybe sounding harsh, but it is my job to say “NO” to new features until their need is proven :-)
Regards,
Roland
On the technical level I believe that aroundReceive already allows full control over the order in which things get stacked: the actor definition itself is the place where the order of mixins or superclasses determines this. Can you point out a specific problem that is not solvable with this and which we actually should want to solve at the toolkit level?
Sorry for maybe sounding harsh, but it is my job to say “NO” to new features until their need is proven :-)
Regards,
Roland
on 2013-11-21 13:20 *
By gaston.tonietti
You're right. I don't want Akka to become the new Spring.
The problem with decorate by overriding is when you need to hook the decoration in optional traits. If you use self type for ensuring mixing with Actor you cannot override the method, so you make the trait extend Actor for being able to override.
Imagine you have 2 traits extending Actor to override arroundReceive, then you have a 3th trait which extends one and mixin with the other. Which override whould win? I think it doesn't use both overrides, in the case it does, which one come first?
Roland, please don't be sorry for doing your job, you're doing it really well. :-)
Gaston.
The problem with decorate by overriding is when you need to hook the decoration in optional traits. If you use self type for ensuring mixing with Actor you cannot override the method, so you make the trait extend Actor for being able to override.
Imagine you have 2 traits extending Actor to override arroundReceive, then you have a 3th trait which extends one and mixin with the other. Which override whould win? I think it doesn't use both overrides, in the case it does, which one come first?
Roland, please don't be sorry for doing your job, you're doing it really well. :-)
Gaston.
on 2013-11-21 14:43 *
By gaston.tonietti
Here you have a NOT working example:
https://gist.github.com/ktonga/7582529
It can be solved by swapping the mixin order:
trait BaseActor extends Logging with akka.ContextualActor
Instead of this one which makes more sense:
trait BaseActor extends akka.ContextualActor with Logging
Not so terrible :-P
Gaston.
https://gist.github.com/ktonga/7582529
It can be solved by swapping the mixin order:
trait BaseActor extends Logging with akka.ContextualActor
Instead of this one which makes more sense:
trait BaseActor extends akka.ContextualActor with Logging
Not so terrible :-P
Gaston.
on 2013-11-21 23:10 *
By viktorklang
OR we switch to a monadic approach where you actually build up a processing pipeline. This can be implemented on top of what's already in place.
on 2013-11-22 10:39 *
By gaston.tonietti
Such a good idea!
What do you think about something like this? https://gist.github.com/ktonga/7597912
Gaston.
@ktonga
What do you think about something like this? https://gist.github.com/ktonga/7597912
Gaston.
@ktonga
on 2013-12-10 10:48 *
By gaston.tonietti
Of course, glad you asked.
Any special guidelines? Or it's the same than contributing to any other module?
Any special guidelines? Or it's the same than contributing to any other module?
on 2013-12-11 05:31 *
By gaston.tonietti
I've created the PR with a first approach. https://github.com/akka/akka/pull/1869