question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Handle request replays by Jetty due to timeout of long-running async request

See original GitHub issue

I’ve encountered an issue with async execution of long-running jobs.

If a back-end service takes longer than 30 seconds to process an asynchronous request, Jetty will replay the request, while setting response code to 500. Javalin will also replay the request as it would a normal request, except that body is this time empty. I wrote a short demo that shows how Javalin handles it. See log output below for details on what goes on. This SO question also mentions it.

(Btw, 30 second timeout is a property defined in org.eclipse.jetty.HttpChannelState.DEFAULT_TIMER and can be set via. system property which is pretty awkward. I haven’t found another way to set it.)

Here’s example code that triggers the timeout (using io.restassured to issue a request):

long asyncTimeout = Long.getLong("org.eclipse.jetty.server.HttpChannelState.DEFAULT_TIMEOUT", 30000);
CompletableFuture<Object> future = new CompletableFuture<>();

Javalin j = Javalin.create();

j.before(ctx -> {
  // cannot access async context here yet
  System.out.println(Instant.now() + " BEFORE disp=" +
    ctx.req.getDispatcherType() + " " + ctx.req.getRequestURI() +
    " " + " body='" + ctx.body() + "' " + ctx.status());
});
j.after(ctx -> {
  System.out.println(Instant.now() + " " + "AFTER uri='" +
    ctx.req.getRequestURI() + "' " + " body='" + ctx.body() + "' " +
    ctx.status() + " result='" + ctx.resultString() + "'");
});

j.get("/async", ctx -> ctx.result(future));

j.start();

Executors.newSingleThreadScheduledExecutor().schedule(() -> future.complete("result"), asyncTimeout + 5000, TimeUnit.MILLISECONDS);

given().port(j.port()).body("{\"param\":\"data\"}").get("/async").then().log().all();

and here is the output, with wire data logged in restassured:

2590  [main] DEBUG wire       -  >> "GET /async HTTP/1.1[\r][\n]" 
2591  [main] DEBUG wire       -  >> "Accept: */*[\r][\n]" 
2591  [main] DEBUG wire       -  >> "Content-Type: text/plain; charset=ISO-8859-1[\r][\n]" 
2591  [main] DEBUG wire       -  >> "Content-Length: 16[\r][\n]" 
2591  [main] DEBUG wire       -  >> "Host: localhost:7000[\r][\n]" 
2591  [main] DEBUG wire       -  >> "Connection: Keep-Alive[\r][\n]" 
2591  [main] DEBUG wire       -  >> "User-Agent: Apache-HttpClient/4.5.3 (Java/1.8.0_112)[\r][\n]" 
2591  [main] DEBUG wire       -  >> "Accept-Encoding: gzip,deflate[\r][\n]" 
2591  [main] DEBUG wire       -  >> "[\r][\n]" 
2591  [main] DEBUG wire       -  >> "{"param":"data"}" 
2018-12-04T20:08:35.365Z BEFORE disp=REQUEST /async  body='{"param":"data"}' 200
2018-12-04T20:09:05.374Z BEFORE disp=ERROR /async  body='' 500
2018-12-04T20:09:08.967Z AFTER uri='/async'  body='' 500 result='result'
36265 [main] DEBUG wire       -  << "HTTP/1.1 500 Server Error[\r][\n]" 
36267 [main] DEBUG wire       -  << "Server: Javalin[\r][\n]" 
36267 [main] DEBUG wire       -  << "Content-Type: text/plain[\r][\n]" 
36267 [main] DEBUG wire       -  << "Content-Length: 6[\r][\n]" 
36267 [main] DEBUG wire       -  << "[\r][\n]" 
2018-12-04T20:09:08.977Z AFTER uri='null'  body='{"param":"data"}' 200 result='result'
36351 [main] DEBUG wire       -  << "result" 
HTTP/1.1 500 Server Error
Server: Javalin
Content-Type: text/plain
Content-Length: 6

result

I haven’t found an explicit way to handle such timeout within Javalin. I don’t really have an opinion on how to improve it due to lack of experience with web servers (highlighted by the fact that I ran into this issue at all by designing a ‘REST’ service that regularly takes 30+ seconds to respond). Sorry 😃

My workaround was to tack a continuation to this task that sets status code to 200. Then I save the task into session attribute on first request and use it on followup requests to re-set Javalin’s ctx.result(CompletableFuture<?>). That messes up request timing, but otherwise seems to work. When the future finishes, I see after handlers being triggered for each request, but only the last one returns to client. I also had to put some code into AccessManager to skip re-authorizing these repeated requests.

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Comments:10 (7 by maintainers)

github_iconTop GitHub Comments

2reactions
tipsycommented, Dec 16, 2018
0reactions
tipsycommented, Jan 14, 2019

@pikob added an option to configure it per request in #465

Read more comments on GitHub >

github_iconTop Results From Across the Web

Handle request replays by Jetty due to timeout of long-running ...
If a back-end service takes longer than 30 seconds to process an asynchronous request, Jetty will replay the request, while setting response ...
Read more >
jetty replay request on timeout - Stack Overflow
You have put the request into async state and then not handled the timeout, so the request is redispatch with a DispatcherType of...
Read more >
Handling long Web Requests with Asynchronous Request ...
Long requests can time out the Web server Web servers are set up with certain timeouts to kill connections after the timeout period...
Read more >
Apache HBase ™ Reference Guide
When an RPC call fails for instance for a timeout due to hbase.rpc.timeout it will be retried until hbase.client.operation.timeout is reached. Client ...
Read more >
Microservices Best Practices for Java - IBM Redbooks
This layer handles basic validation of requests and then passes the information into the domain logic layer. Domain logic, as a general concept,...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found