playframework / playframework/play-ebean
@Transactional and TransactionalAction conception problem - does not work with Secure Social plugin
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 111
- Forks
- 67
- Avg merge
- 1d 11h
- Merged PRs (30d)
- 19
Description
Hi,
I've found a critical bug in the play java ebean plugin.
In my opinion, there is a confusion in the usage of promise and action wrappers (@With ...).
Look at this portion of code from the class play.db.ebean.TransactionalAction: (https://github.com/playframework/play-ebean/blob/268c771426398353af39c0c45fb458122cc57a6b/play-ebean/src/main/java/play/db/ebean/TransactionalAction.java)
/**
* Wraps an action in an Ebean transaction.
*/
public class TransactionalAction extends Action<Transactional> {
public F.Promise<Result> call(final Context ctx) throws Throwable {
return Ebean.execute(new TxCallable<F.Promise<Result>>() {
public F.Promise<Result> call() {
try {
return delegate.call(ctx);
} catch (RuntimeException e) {
throw e;
} catch (Throwable t) {
throw new RuntimeException(t);
}
}
});
}
}
The EBean transaction starts before entering the public F.Promise<Result> call() method, and is commited or rollbacked depending if there is an exception thrown at the end of call().
In this callable, the result of delegate.call(ctx) is returned. This result is of kind F.Promise<Result>.
A promise is a "promise of response", but nothing tell us that the underlying action has already been executed after the delegate call. Moreover, nothing tell us that it will be executed in the same thread.
In the common case where no play plugins are used, this portion of code works: but I insist on the point that this case is a special case, because I don't know why but when the F.Promise is returned, the underlying action has already been executed in the current thread. I think that this is a misconception but that's my opinion.
Moreover nothing forbid in the current API to execute the delegate action in another thread and later (I mean after the transaction commit).
For example, if you use the popular and almost vital plugin Secure Social, this code does not work anymore. There is no exception thrown, but the subsequent action is executed outside the transaction, and this is a very bad idea.
Indeed, in this case, the delegate returns a F.Promise where the action has not yet been executed. And again, I insist on the point that this is not a Secure Social bug in my opinion because the promise API is made to allow that!
For information, I'm using Secure Social 3.0-M3 and Play Framework 2.3.8.
Currently, I'm trying to understand how to really "wrap" the action execution using the F.Promise API, but any help would be really appreciated.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with play-ebean/src/main/java/play/db/ebean/TransactionalAction.java and trace how delegate.call(ctx) returns an F.Promise relative to the Ebean transaction lifecycle. Reproduce the behavior with the Secure Social integration described in the issue, then verify that the delegated action executes within the transaction and that commit or rollback occurs only after it completes.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- database
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 30/100