-
Notifications
You must be signed in to change notification settings - Fork 142
Alter the library methods to propagate an implicit ExecutionContext #342
Conversation
Forgot to add that it pass all tests. I had to change the tests due to the extra ExecutionContext parameters. |
@@ -24,10 +24,11 @@ import com.mohiva.play.silhouette.api.services.AuthenticatorResult | |||
import com.mohiva.play.silhouette.api.util.DefaultEndpointHandler | |||
import play.api.Play | |||
import play.api.i18n.{ MessagesApi, I18nSupport } | |||
import play.api.libs.concurrent.Execution.Implicits._ | |||
////import play.api.libs.concurrent.Execution.Implicits._ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment can be removed
You are my hero! Really! This was the next task on my to do list and now you save me a lot of time. There are two things I've noticed. The first are the comments with the old implicit execution context. They are widespread over the complete project. These should be removed. The other is a question regarding the equality matcher you've used in the tests: env.identityService.retrieve(===(identity.loginInfo))(any) returns Future.successful(None) Why is it necessary now? Could you also explain what the smart mock does? I'm not aware of such a functionality. @rfranco Please could you also review the pull request? |
Sorry about the comments. I thought I had removed then before commiting. |
About the smart mock: I had some problems with null values being returned from unexpected unstubbed methods after I started adding the ExecutionContext parameters. |
Ahhh, now I see. Thanks for the explanation. |
@akkie I'm traveling now and i'll be back Tuesday then i can do better review so i did a quick review and looks great anyway maybe it could be done as we did with |
In an hour. |
@akkie @rfranco The build failed in a test. I don't see what the problem is. In my local code the tests run ok. On CookieSecretSpec: [info] The |
@joaoraf The test error has to do with playframework/playframework#3120. Maybe we should change the test. Anyway, this shouldn't be a part of this pull request. Please could you squash the commits into a single commit. Otherwise, for me it looks ready to merge. |
@joaoraf I think the Authorization.isAuthorized method needs also an execution context. |
8151161
to
ddc150d
Compare
@akkie everything tested and squashed. |
@joaoraf The import comments are still available. |
Damned squashing! |
I reviewed the code and i'm not sure about add ExecutionContext in everyplace. One example is if create a class FooIDGenerator() extends IDGenerator {
def generate(implicit ec: ExecutionContext): Future[String] = Future("foo")
} VS class FooIDGenerator(implicit ec: ExecutionContext) extends IDGenerator {
def generate(): Future[String] = Future("foo")
} My suggestion is to review all place where need |
@rfranco What do you think? Whatever you decide, I will try to make it. Another path is to make it configurable somehow, allowing the user to choose (or inject) ExecutionContexts where such are needed. |
I see it similar to @joaoraf. An execution context should be defined context bound and not at initialization time(for classes that gets typically injected). For helper or internal classes that gets typically constructed inside the code, a constructor injected execution context makes sense. I've searched through Play, Slick, ReactiveMongo and Akka, and all the projects prefers the execution context on the method instead of the constructor. Anyway, I'm not sure if the execution context must be defined as argument on every method which returns a |
Remember that you need a ExecutionContext whenever you manipulate a future using map, flatMap, etc. To create a Future you also need an ExecutionContext. What I believe should be avoided is the need to use the "scala.concurrent.ExecutionContext.global" execution context just because there is none when you need, for example, to map (or flatMap) the value of a future before returning to the caller. |
@akkie @joaoraf agree with both usually i prefer to inject So we really should review all the methods and see which need each approach by method or constructor. |
@joaoraf I meant methods that gets implemented by the user itself. Because the user can then define which execution context should be used. For methods that are already implemented by us the user should be able to pass the execution context. Here are some examples for methods that gets implemented by the user: DAOs, Services and repositories gets also implemented by the user. And I'm really unsure if it's the best approach to let the user handle the different methods over different execution contexts. So I'm with @rfranco here, to let the user inject the execution context if needed. Anyway, I'm really unsure about the right approach. If I see it right then the current implementation provided by @joaoraf gives a user the possibility to define the execution context on controller level and then let the Silhouette depended code run in this execution context. A user is also able to define an other execution context in sub components of Silhouette. If we implement only constructor injection of the execution context, then the user can only define the execution context for all controller instances and the dependent Silhouette classes once. As like with the other approach a user is able to define another execution context in sub components of Silhouette. So the main question should be: Should the execution context be defined once or should it be defined per logically-related section of code? From the doc:
|
Can we find any consensus here? |
Since Silhouette is intrinsically coupled to Play, we could use Play's ExecutionContext, which we can obtain through play.current or through the request (I believe) all way up to the calls to Services and Repositories (avoiding passing it through the call chain). The Services and Repositories then decide what they will use. They can use the Play's execution context also. We should just warn the user to avoid using the global execution context, using the Play one instead if they don't require a separate context for the Repository/Service. As I said, whatever you decide I help implement. I am getting used to trace all these calls on the code ;-) |
I've created a topic is the Scala-Users mailing list with the title "Best strategy to pass the ExecutionContext for a library". Maybe this can help us to find the best solution. |
A very very nice discussion by the way. It seems this affects many people. |
@joaoraf Would it be OK for you if I create a new pull request. I find it hard to make decisions based on this pull request. I think I must rummage through the code to find the places which needs the |
No problem. Do you want some help? Have you decided the strategy? |
Fixed with #360 |
Details on issue #341.