1. What really happens when people visit the site? It's only one ./app that's running. Does a new thread get created within this same app whenever each user triggers a get "/:word" $ do line? How many such threads can exist? Thousand? Ten thousand?
Scotty is build around warp, but could use any other library that implements the web application interface (WAI). A new lightweight thread gets created with forkIOUnmasked
(hidden in fork
in the module Network.Wai.Handler.Warp.Run
). You can have many of those:
Concurrency is "lightweight", which means that both thread creation and context switching overheads are extremely low. Scheduling of Haskell threads is done internally in the Haskell runtime system, and doesn't make use of any operating system-supplied thread packages. (source)
Here's a performance comparison between nginx and warp, which also includes information about the general idea behind warp.
2. After running ./app it shows the message Setting phasers to stun... (port 3000) (ctrl-c to quit). But it shows nothing more. It doesn't output the incoming web requests. How can I make it do that? This would be useful for logging purposes.
What's the type of your do
block? It should be ScottyM
, since scotty :: Port -> ScottyM () -> IO ()
. If ScottyM
is an instance of MonadIO
, you can use liftIO
together with putStrLn
(or any other IO
action).
Now, ScottyM
is actually a type synonym for ScottyT
, which is in fact a instance of MonadIO
. Also, the inner monad ActionM
is also a type synonym for ActionT
, which is also a MonadIO
. Therefore, logging is as easy as
main = scotty 3000 $ do
liftIO $ putStrLn "incoming request"
get "/:word" $ do
beam <- param "word"
liftIO $ print $ mconcat ["get, word = ", beam]
html $ mconcat ["<h1>Scotty, ", beam, " me up!</h1>"]
However, keep in mind that logging to a terminal might not be a good idea when you really expect ten thousand requests per second.