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.

Implementation of future request handling is not thread-safe and may lead to unexpected behaviours

See original GitHub issue

A few days ago I was reading async part of request handling. I’ve found up an interesting fact - result future is always accessed through resultFuture() method call on mutable context. Well…, finally found some time to confirm these observations - the async context implementation is not thread-safe and may lead to some improper behaviors, especially in high-load environments.

What’s the problem?

By checking this condition Javalin determines if request should be handled sync/async:

https://github.com/tipsy/javalin/blob/2eb9211d96de713a3b9e24ba45189145caba11e7/javalin/src/main/java/io/javalin/http/JavalinServlet.kt#L87

And now we can be pretty much doomed, because further request handling still refers to the future stored in mutable filed in Context. For instance:

  1. User sets CompletableFuture as a result and delegates this task to some other thread pool to complete this task
  2. Javalin receives future result and starts async handling with code linked above
  3. User’s thread pool got priority and completed queued task where user responded with a new result that cleaned up current future https://github.com/tipsy/javalin/blob/2eb9211d96de713a3b9e24ba45189145caba11e7/javalin/src/main/java/io/javalin/http/Context.kt#L345
  4. Thread context restored, Javalin got some time to complete async context initialization
  5. Oopps, ctx is now corrupted, because future has disappeared. It may affect various things, e.g.:

It’s quite breaking, because it completely breaks request and leads to difficult to define behaviors. For now I see at least 2 solutions:

  1. Store future result as a variable to at least guarantee built-in initialization phase. (fast)
  2. Provide some kind of a field that preserves future result of the current context (better, might be considered in the future). Let’s say that future result might be set only once in the Context and it shouldn’t be cleaned up.
Example exception
16:42:49.103 ERROR | Exception occurred while servicing http-request: java.lang.NullPointerException
        at io.javalin.http.JavalinServlet.service(JavalinServlet.kt:98)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
        at io.javalin.jetty.JavalinJettyServlet.service(JavalinJettyServlet.kt:58)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
        at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:799)
        at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:550)
        at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:233)
        at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1624)
        at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:233)
        at io.javalin.jetty.JettyServer$start$wsAndHttpHandler$1.doHandle(JettyServer.kt:52)
        at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:188)
        at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:501)
        at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1594)
        at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:186)
        at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1349)
        at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
        at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127)
        at org.eclipse.jetty.server.Server.handle(Server.java:516)
        at org.eclipse.jetty.server.HttpChannel.lambda$handle$1(HttpChannel.java:388)
        at org.eclipse.jetty.server.HttpChannel.dispatch(HttpChannel.java:633)
        at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:380)
        at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:277)
        at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:311)
        at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:105)
        at org.eclipse.jetty.io.ChannelEndPoint$1.run(ChannelEndPoint.java:104)
        at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:338)
        at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:315)
        at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:173)
        at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:131)
        at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:386)
        at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:883)
        at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:1034)
        at java.lang.Thread.run(Thread.java:748)

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:8 (8 by maintainers)

github_iconTop GitHub Comments

1reaction
tipsycommented, Sep 13, 2021

I’m happy you found this (and surprised it hasn’t been found before).

0reactions
tipsycommented, Sep 13, 2021

Thank you ❤️

Read more comments on GitHub >

github_iconTop Results From Across the Web

Implementation of future request handling is not thread-safe and ...
It's quite breaking, because it completely breaks request and leads to difficult to define behaviors. For now I see at least 2 solutions:...
Read more >
ASP.NET Core Memory Cache - Is the GetOrCreate method ...
In this blog post I will be researching a common question raised on forums like StackOverflow: "Is the GetOrCreate method thread safe?".
Read more >
Design Decisions — Simple Injector 5 documentation
Problems with thread-safety can easily emerge when the user changes a registration during a web request. If the container allowed such registration change ......
Read more >
Multithreading and concurrency fundamentals - Educative.io
Thread safety is a concept that means different threads can access the same resources without exposing erroneous behavior or producing ...
Read more >
Thread Safe Concurrency ⋆ Mark McDonnell - integralist
Regardless of programming language or idiom that you use, the practice of programming a “thread-safe” application can be harder than you ...
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