-
Notifications
You must be signed in to change notification settings - Fork 95
Consider forcing Uni return types on all Session opening methods #950
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
Comments
cc/ @gavinking I'd be keen to hear you opinion on this one. |
Well if I understand correctly, your helper method is simply wrong. We document fairly clearly, I think, that sessions obtained with |
I'm not expecting propagation, I'm passing the My only error was in expecting that I could actually use such a Session for composite operations, such as loading multiple entities with individual statements |
Then I just don't understand your code. You open one session, then you do the I don't understand the logic there. |
Well, TBH, perhaps it's not that well documented... |
I think @Sanne's example was supposed to be:
|
Aaah OK that makes more sense. |
Well if that's the case then that would be a bug. But to be really honest I'm simply having some trouble believing you Sanne. Every time someone has complained about the proxy, it has turned out to be misuse of the session. I've stared at that code really hard in the past, and I've always managed to convince myself it's right. |
oops yes sorry wrong code example. I've been going back and forth with various experiments.
I totally understand the feeling, we've had many such cases and most often there was some mistake in the user code, or tricky threading. In this case though while I was 99% sure I was making some mistake, I then asked Davide to help me out as I couldn't figure it out - but this time around my conclusion was that really returning an Tangentially, but we also concluded that my code was OK in this case :) And that worries me a apparently this idea of the connection proxy is making things really tricky. And as I mentioned, all integration code I know of would actually prefer dealing with an Uni. I guess we should make a test for Hibernate Reactive for you to see, that would simplify the discussion - I can't do that today though. |
I mean, this code works perfectly: public <T> Uni<T> inSession(Function<Mutiny.Session, Uni<T>> work) {
final Mutiny.Session session = getMutinySessionFactory().openSession();
return work.apply(session).eventually( session::close );
}
@Test
public void method(TestContext context) {
test( context, inSession(
(s) -> s.persist(new GuineaPig( 5, "Aloi" ))
.call( () -> s.persist(new GuineaPig( 6, "Pig" )))
.chain( ()-> s.createQuery("from GuineaPig").getResultList() )
).invoke( list -> context.assertEquals(2, list.size() )) );
} and so I can't imagine how it could break unless you're doing something dodgy with concurrency. |
Well if you recall when I made that change last time, everyone rebelled against it and talked me out of it. So I'm kinda wary of going back there. |
So, I failed miserably in reproducing the issue in the context of an Hibernate Reactive integration test, but it fails consistently in the benchmark (even without load, it fails on a single call). The cause seems to be this code in which I need to load a bag of entities by having the set of Ids: this fails (in the benchmark only) when using the
The problem seems to be that The documentation rightfully points out something related [http://hibernate.org/reactive/documentation/1.0/reference/html_single/#_obtaining_a_reactive_session]
So changing the operation to explicitly chain all ops will work fine:
So this raises multiple questions:
|
Well, right, at least as far as I've always understood it, |
Initially it sounded nice to have So I wouldn't mind to reconsider our position now that we have more experience. EDIT: I've removed some already mentioned points |
Well no, I don't think that's right. The connection isn't the only volatile state held by the session; far from it. |
Oh, looks like I responded to text you deleted. |
I think you guys need to consider that changing the return type of |
I suppose you're using the term "threadsafe" loosely in this context, in which case I agree with you.. but let me be precise in case we're misunderstanding each other: this is all running on the same, single thread, so the canonical definition of "threadsafe" doesn't really apply. We might need to clarify some things in the doc.
But that's the point I'm raising. IFF there a real problem with using As things stand, we only fail hard if you're using the current On the other hand, IFF we state that using There's a third alternative: I have a local POC which adapts the |
Right.
Well, how? We already do the best we can, by checking at the Vert.x context. Apparently that's not good enough to detect the problem in this case, but I don't see what else we could do if Mutiny doesn't expose some sort way to identify the "micro-context". |
Ok fair enough. So the conclusion is that using |
Well it's not that I don't want to it's that I have no idea how to. |
this would make it work: I'm just not sure if we want to :) And what other issues I'm possibly missing. |
I don't see how that would fix the generic problem of concurrent access to volatile session state. During every single (nonblocking) database request, the session is in an inconsistent state. I don't see how you can fix that without having some sort of "transactional" management of the session's internal data structures. |
Ok yes I think I understand what you mean, although I'm not sure in practice which scenarios would be problematic; for sure this would work just fine for loading a sequence of trivial entities with no relations among each other (as I was doing here). So while we agree that multi-threaded access on the same Session is a big no-no, I'm not sure how far we can expect a "reactive programmer" to not issue subsequent requests for data operations without honouring a strict chain of operations - doesn't that defeat the purpose of the model? As far as I had understood, one of the significant benefits of reactive programming is that it becomes unnecessary to explicitly load N items in bulk, as one can just start requesting each of the N items one by one and effectively have them returned at a similar total dealy. IMO this is a big limitation which we should look at better; specifically I'd love to see specific tests leading to inconsistent Session state, so to possibly wrap our head around it in a more concrete way. |
I'm not sure how I feel about this. If a user uses Making the signature of the method reactive has also the benefit of simplifying the code and I suspect it will save us some headaches in the future. |
Nope, it's never fine. It's not fine in regular Hibernate, and it's not fine here. (There's absolutely nothing in what I've said here that's specific to Reactive, FTR.)
I think the much more relevant question here is: for someone who does want to manage their own reactive I'm not quite clear on what the answer to that is. |
You mean, for example, what's more convenient between |
I'm not entirely sure either, but I have a draft of adapting Quarkus (and Panache Reactive) to deal with |
I mean what's more convenient for someone implementing that sort of injection, for example. |
It's not necessary now that all the openSession methods return a Uni or CompletionStage
It's not necessary now that all the openSession methods return a Uni or CompletionStage
It's not necessary now that all the openSession methods return a Uni or CompletionStage
I've got burned once again by chaining the wrong style of Session opening.
This is what I had as a general helper:
(This is very similar to the
withSession
helper offered onMutinySessionImpl
, but I was needing to intentionally side-step the use of theorg.hibernate.reactive.context.Context
- details not relevant now)When I'm passing as
work
argument a trivial work which does a single operation on the session, this works as expected.But if I use such an helper method with a slightly less trivial work, such as needing to load more than one entity, the second load operation is likely going to hit the infamous error we already know quite well:
In this case, I am sure that this was all run on the same vert.x context (and the same thread); with @DavideD 's help we figured out the problem is that the
Mutiny.Session
instance opened this way is not fit to be used more than once, because the composition of multiple operations on it can't guarantee that the session proxy is being initialized once and atomically.I would propose to remove the
Session openSession();
method and its siblings dealing with tenant-id and stateless sessions, to be replaced with methods which return theUni<Session>
,Uni<StatelessSession>
, etc...Impact:
Uni<Session>
- the only exception being theboolean isPersistent(Object entity)
method which Panache Reactive exposes, but we can either deal with that by using the context, or update the signature to also become a reactive method.The text was updated successfully, but these errors were encountered: