multithreadinghaskellghchaskell-warp

throwTo warp tls thread hangs idefinetly


I have a Yesod app with a warp server, and some of its functionality depends on async exceptions. Recently there arose a need to migrate it to https, which I did with the package warp-tls. However now I can't kill the warp thread by throwing ThreadKilled exceptions at it, the throwTo function just hangs and does nothing.

Consider the following example. Here we monitor the state of warp thread with MVar (), which is empty while the thread is running, and has a () value when the thread is killed.

import MyApplication (waiPage)
-- waiPage :: Application

runWai :: MVar () -> IO ()
runWai finishVar = bracket
  (return ())
  (const $ putMVar finishVar ())
  (const runApp)
  where
    -- change this to normal or tls to check
    runApp = runAppTls
    runAppNormal = runSettings warpSettings waiPage
    runAppTls = runTLS siteTlsSettings warpSettings waiPage
    --
    warpSettings = setPort 8080 defaultSettings
    siteTlsSettings = tlsSettings "cert.pem" "key.pem"



main :: IO ()
main = do
  finishVar <- newEmptyMVar
  thread_id <- forkIO $ runWai finishVar
  -- Try to kill warp thread. Fork because throw might hang
  forkIO $ throwTo thread_id ThreadKilled
  threadDelay (2 * 10^6) -- microseconds to seconds
  isAlive <- isEmptyMVar finishVar
  if isAlive then putStrLn "Couldn't kill warp thread"
             else putStrLn "Succesfully killed warp thread"
  -- Wait for forked warp thread to finish
  readMVar finishVar

When you have runApp = runAppNormal, you will get Succesfully killed warp thread message, and the application will exit.

When you have runApp = runAppTls, you will get the Couldn't kill warp thread message, and the app will hang and keep serving.

So how do I get rid of this exception-intercepting behavior? Or at Least is there a way to kill the warpTls thread in any other way?


Solution

  • It turned out to be a Windows-only bug in the version I used which is warp-tls == 3.2.4 that got fixed in a later version. I've looked at the fix and it's a function with the name windowsThreadBlockHack, so if anyone is stuck with a bit outdated warp, you can backport this fix for you too.