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

Fix for Context Propagation on Reactive Messaging #27802

Conversation

ozangunalp
Copy link
Contributor

@ozangunalp ozangunalp commented Sep 8, 2022

The issue revealed by @Sanne in https://github.com/Sanne/quarkus-scope-tests

Reactive Messaging doesn't handle CDI request scope, it only ensures that consumer methods are dispatched on a duplicated vert.x context per message.
When a request scoped bean is used in consumer methods, the request context should not be active by default and can be activated through the @ActivateRequestContext annotation, properly creating request scoped beans and destroying them on completion.

The fix involves:

  • Run reactive messaging wiring without RequestContext
  • ActivateRequestContextInterceptor terminates request context properly on returning Uni.
  • ActivateRequestContextInterceptor destroys request context state properly when reactive method completes on a different thread (or a different Vert.x context)

A separate PR will follow on smallrye-reactive-messaging for returning message (n)ack's on the message context.

Fixes #27166

@quarkus-bot quarkus-bot bot added area/arc Issue related to ARC (dependency injection) area/reactive-messaging area/smallrye labels Sep 8, 2022
try {
mediatorManager.start();
} catch (Exception e) {
if (e instanceof DeploymentException || e instanceof DefinitionException) {
throw e;
}
throw new DeploymentException(e);
} finally {
if (isRequestScopeActive) {
Arc.container().requestContext().activate();
Copy link
Member

@Sanne Sanne Sep 8, 2022

Choose a reason for hiding this comment

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

I really don't know, but I'm wondering if the initial request context shouldn't be restored rather than a new one being activated? Are we ok to throw a way the context state?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

When you say it, it makes sense. I've done as you suggest, but I didn't resolve the conversation to double check

Copy link
Contributor

@Ladicek Ladicek Sep 9, 2022

Choose a reason for hiding this comment

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

I think this makes sense.

EDIT: as it is now, I mean. Restoring the original request context.

@Sanne
Copy link
Member

Sanne commented Sep 8, 2022

Thank you so much for digging! I'll let others review though, my knowledge of CDI semantic expectations is too limited.

ActivateRequestContextInterceptor : Destroy request scope property when reactive method returns on different thread
@ozangunalp ozangunalp force-pushed the fix_context_propagation_reactive_messaging_request_context branch from 0bd1f6c to 0f32c84 Compare September 8, 2022 16:48
@mkouba mkouba requested a review from Ladicek September 9, 2022 09:05
.thenCompose(state -> proceedWithStage(ctx).whenComplete((r, t) -> {
requestContext.destroy(state);
requestContext.deactivate();
}));
Copy link
Contributor

Choose a reason for hiding this comment

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

I was wondering what's the difference here, as terminate() == destroy() + deactivate(). It's that you explicitly pass state to destroy, right?

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah all changes in this file do this same thing. I wonder if it's just a precaution, or if destroy() without parameters finds (and destroys) a different context than it should...

In any case, being explicit can't hurt.

Copy link
Contributor Author

@ozangunalp ozangunalp Sep 9, 2022

Choose a reason for hiding this comment

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

Exactly, otherwise it'll destroy the state from the current context.

@Sanne
Copy link
Member

Sanne commented Sep 9, 2022

There seems to be a problem in my reproducer still; although I'm not sure if my test is valid or perhaps I have some invalid assumptions.

W/o this PR, I was having org.acme.GreetingResourceTest passing, and org.acme.GreetingKafkaTest fail.

But with this patch appied, while the Kafka one seems fixed, the other one starts failing - I need to look better into it but it seems to indicate a new leak.

@Sanne
Copy link
Member

Sanne commented Sep 9, 2022

Nevermind, I had a problem in my test.
Thanks!

@ozangunalp
Copy link
Contributor Author

@Sanne I forked your test and added some more here: https://github.com/ozangunalp/quarkus-scope-tests, with this branch they all pass for me.

@Sanne
Copy link
Member

Sanne commented Sep 9, 2022

Right, seems all good. I'm verifying now if it also fixes #27166

@Sanne
Copy link
Member

Sanne commented Sep 9, 2022

@gsmet N.B. I've marked this both as candidate for backporting and as breaking change (!).

  • I'd consider it for backporting as it fixes a nasty leak, of both resources and memory (see e.g. now fixed Connection pool exhaustion for lazy entity association (acquisition timeout) #27166) : scopes were started but never terminated. New scopes would pile up without being reused.
  • it's breaking as with this fix, people having a listener might need to start a request scope explicitly; for example they might need to add @ActivateRequestContext on the receiving method. Essentially the lifespan of the scope is safer to be made explicit by the user in this case.

@gsmet
Copy link
Member

gsmet commented Sep 12, 2022

It's not backportable, removing the label.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Connection pool exhaustion for lazy entity association (acquisition timeout)
4 participants