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

ArCContextProvider does not propagate request context #3186

Closed
FroMage opened this issue Jul 11, 2019 · 8 comments
Closed

ArCContextProvider does not propagate request context #3186

FroMage opened this issue Jul 11, 2019 · 8 comments
Assignees
Labels
area/arc Issue related to ARC (dependency injection) area/reactive kind/bug Something isn't working
Milestone

Comments

@FroMage
Copy link
Member

FroMage commented Jul 11, 2019

As explained on Zulip and eclipse/microprofile-context-propagation#167, the current ArcContextProvider does not allow propagation of the request context, because it captures/restores values instead of the entire context.

We need to fix this because ATM it can't be used by reactive applications, which is the whole point of MP-CP.

Reproducer:

    @Inject
    MyRequestScopedBean bean;
    @Inject
    ThreadContext ctx;
    
    @GET
    @Path("datatypes")
    public CompletionStage<String> testRxDataTypes() {
        return ctx.withContextCapture(CompletableFuture.completedFuture(null))
                .thenApply(v -> bean.instanceCount())
                .thenApply(v -> {
                    Assertions.assertEquals(1, bean.instanceCount()); // should have only one bean per request
                    
                    return "OK";
                });
    }

    @GET
    @Path("datatypes-destroyed")
    public String testRxDataTypesDestroyed() {
        Assertions.assertEquals(1, bean.destroyed); // should have destroyed the previous request bean
        return "OK";
    }
@RequestScoped
public class MyRequestScopedBean {
    
    static int count;
    static int destroyed;
    
    @PostConstruct
    public void init() {
        // open a DB connection for this request
        count++;
    }
    
    @PreDestroy
    public void destroy() {
      // close a DB connection for this request
      destroyed++;    
    }
    
    public int instanceCount() {
        // how many DB connections have we opened so far?
        return count;
    }
}

Then make two REST calls to /datatypes then /datatypes-destroyed and observe that we create more than one request bean per request, and destroy a total of zero of them.

@FroMage FroMage added kind/bug Something isn't working area/reactive area/arc Issue related to ARC (dependency injection) labels Jul 11, 2019
FroMage added a commit to FroMage/quarkus that referenced this issue Jul 11, 2019
@manovotn
Copy link
Contributor

    @PreDestroy
    public void destroy() {
      // close a DB connection for this request
      destroyed++;    
    }

This won't really work because CDI doesn't know when the request is truly over. The propagation is done in a way that the next task activates request scope (with no link to actual original HTTP request) and once done it tears it deactivates the context but deliberately doesn't destroy is hence @PreDestroy callbacks won't execute. I've even added some docs on that to Weld, but I suppose nothing was noted for Arc even though it behaves equally.

If the predestroy callback execute:

  • In sequential scenario, you would destroy the bean n-times while still having it active in next step which is just wrong
  • In parallel scenario, there is less harm but the bean can operate on some other wider-scope bean (app scoped) and trigger the same logic repeatedly

Furthermore, in parallel scenario you don't really know which propagation step (which thread) is 'eligible' to say "Hey, this is where the request ends!" even if you had the 'shared map' situation.

I've planned a call with @mkouba to discuss possible solutions in Arc.

@FroMage
Copy link
Member Author

FroMage commented Jul 12, 2019

Well, I've switched to an implementation that copies the mutable Map and I do get the context properly destroyed when the request context is destroyed by the underlying http request. So it works, really.

@FroMage
Copy link
Member Author

FroMage commented Jul 12, 2019

It's destroyed in UndertowDeploymentTemplate when the async request is over, as is proper. If you try to copy the context state instead of propagating the entire mutable request context, I don't think you can implement destroy properly.

@FroMage
Copy link
Member Author

FroMage commented Jul 12, 2019

Though I see now it destroys a copy of the request state and not the entire request, so the same problem can happen. I'm not sure why it works in my test then.

@FroMage
Copy link
Member Author

FroMage commented Jul 12, 2019

But it's easily fixable as well.

@manovotn
Copy link
Contributor

FroMage added a commit to FroMage/quarkus that referenced this issue Jul 15, 2019
@manovotn
Copy link
Contributor

A draft of what me and Martin came up with is here - #3243
It basically shares the map but indirectly via an interface so that the map isn't publicly exposed.

@FroMage
Copy link
Member Author

FroMage commented Jul 17, 2019

Thanks!

@FroMage FroMage closed this as completed Jul 17, 2019
@FroMage FroMage added this to the 0.20.0 milestone Jul 17, 2019
FroMage added a commit to FroMage/quarkus that referenced this issue Jul 17, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/arc Issue related to ARC (dependency injection) area/reactive kind/bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants