eclipse-ee4j / eclipse-ee4j/jersey

Jersey async client race between future and callback

Open
#3,320 3 comments 0 reactions 0 assignees View on GitHub
Component: core Priority: Major Type: Bug
Dominant language
Java
Stars
730
Forks
382
PR merge metrics
No merged PRs in 30d

Description

Hi,

testing async code, I encountered a race condition I believe between callbacks and futures.

My scenario: I need to get 400 Post requests out as quickly as possible. I decided to go with async requests and let jersey handle everything else. My code looks slightly like that:

// create lists of messages to get out
// submit 10 messages to one worker thread
// worker thread submits async call with callback to jersey:
Future post = request.async().post(Entity.entity(postBody, MediaType.APPLICATION_JSON_TYPE), callback);
// callback reacts to failures and success by tracking the key to the status

After this, i need to release all messages, so I wait for jersey to finish processing like this:

for(Future f : collectedFutures)

{ f.get(3000, TimeUnit.Milliseconds); }

This code works fine, no timeout/interrupts or anything similar thrown.

However, when releasing all messages, I take the callback (which tracked all statuses) and release the messages based on their status. (success,retry etc).

Turns out, at that point, even though the get() has returned, the callback has not yet been invoked. In my logs I can see that the callback is invoked around 50-100ms later, so I believe this is a race between jersey marking the Future as done, and notifying the callback with the result, and the get() method returning when finished.

I believe the future should ONLY return the get() call if the callback has been invoked (if there is a callback).

My current workaround is to process the futures in addition to the callback. So that if the callback is not on time, the future can process the status separately. This sort of duplicates code, but I couldn't find a different workaround.

I believe the issue here is in JerseyInvocation#933 and friends. The callback function is not overwritable, and it clearly sets the future to be complete before invoking the callback.

Please let me know if you have any questions
#### Environment
Mac OS 10.10.5,
Jersey-client 2.22.1
Eclipse 4.5.0
#### Affected Versions
[2.22.1]

Contributor guide

Open the contributing guide

Research direction

Start by reading JerseyInvocation#933 and the surrounding async Future and callback handling. Reproduce the Jersey-client 2.22.1 scenario with an asynchronous POST, then verify that Future.get() and callback invocation occur in the intended order. Done means the race is resolved and coverage confirms the callback has run when get() returns.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
api
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.