3 ms·
Let’s say I want to do something simple but slightly beyond the scope of a traditional toy demonstration: * Read some environment variables and a local file *
by opportune 3y ago
Let’s say I want to do something simple but slightly beyond the scope of a traditional toy demonstration:
* Read some environment variables and a local file
* Start a monitoring thread that consumes from a channel or something similar, then every X s or X events writes to a local temp file and then sends a request batching some metrics to an external system
* Configure and start an http server
* Said server has a handler that 0. Starts a timer 1. loads, then increments an atomic “num requests served until now” variable 2. uses synchronization to lock on a list or ring buffer containing the last 5 requests’ user-agent headers 2.5 copies the current last 5 values, replaces oldest one with the one from the handles request, unlocks 3. generates a json response containing like “num_so_far: x, last5agent: [..], “some_env_var”:..” 3.5 stops the timer 4. write request user agent and time interval to monitoring thread’s channel 5. write response and end handling
* server’s gotta be able to do concurrency > 1 with parallelism
* On sigterm set the server to a state that rejects new requests, waits for existing requests to complete, then flushes the monitoring channel
I’d consider this a trial run of some of the most basic patterns commonly used by networked software: init io, immutable shared state, atomic mutable shared state, synchronization locked shared state, http ingress and egress, serialization, concurrency, parallelizarion, background threads, os signals, nontrivial cleanup. In Go, Java, or C++ I could write this with my eyes closed. How easy is it in Haskell or Lisp?
If you know of any demos or repos that do something like this - not a pure toy or barebones demo, but not a huge task all in all- in either I’d be interested in seeing what it looks like.
- remexre 3y agoI'll cover the Haskell side because I'm more familiar with its library ecosystem: > Read some environment variables and a local file import System.Environment (getEnv) import System.FilePath ((</>)) main = do dir <- getEnv "WHATEVER_DIR" data <- readFile (dir </> "foo.txt") putStrLn ("Had " ++ show (length (lines data)) ++ " lines") > Start a monitoring thread [...] import Control.Concurrent import Control.Concurrent.Chan import Network.HTTP -- also more stuff... monitoringThread :: Chan String -> IO () monitoringThread chan = do file <- openFile "log.txt" AppendMode forever $ do -- no $ needed if you pass -XBlockArguments [0, 1] batch <- replicateM 5 (readChan chan) let chunk = unlines batch hPutStr file chunk simpleHTTP (postRequestWithBody "" "text/plain" chunk) main :: IO () main = do logChan <- newChan void (forkIO (monitoringThread logChan)) -- ... forever $ do threadDelay (1000 * 1000) -- 1M usec writeChan logChan "Hello, world!" > Configure and start an http server import Network.Wai import Network.Wai.Handler.Warp main = run 8000 $ \req respond -> respond (responseLBS status200 [] "Hello, world!") > Said server has [...] Yeah, this is long. If you're just getting the current time with the timer, that's here[2]; synchronize across threads with MVars[3] or STM[4]; JSON is in aeson[5], which should feel broadly familiar if you know Rust's serde. > server’s gotta be able to do concurrency > 1 with parallelism Yep, GHC Haskell has _excellent_ concurrency support on top of a parallel runtime. > On sigterm set the server to a state that rejects new requests, waits for existing requests to complete, then flushes the monitoring channel I haven't personally tried this, but this[6] function sounds like... exactly this, actually, so I think its example should suffice? On two separate notes: - Common Lisp and Python 3 are a _lot_ closer than Common Lisp and Haskell, or even Python 3 and JavaScript; the Python 3 object model is very close to Common Lisp's, and Common Lisp is not particularly pure (setf isn't unidiomatic by a longshot), and supports a very non-functional style of programming (it has gotos!). - "Haskell is worse at IO than other high-level languages" isn't particularly true. What _is_ true is that Haskell has the same "function coloring problem" as JavaScript (Haskell has the IO monad, JavaScript has the Promise monad); Haskell also has a "uses funny academic words" problem (well, debatably a problem...) which I think confuses the issue. [0]: https://ghc.gitlab.haskell.org/ghc/doc/users_guide/exts/block_arguments.html https://ghc.gitlab.haskell.org/ghc/doc/users_guide/exts/bloc... [1]: Haskell has a spec, one "main" implementation (GHC), little spec-committee activity, and a respect for that implementation not superseding the spec; many improvements become language extensions (-X flags or {-# LANGUAGE #-} pragmas), so when you invoke GHC you're getting a by-the-spec implementation by default. [2]: https://hackage.haskell.org/package/time-1.12.2/docs/Data-Time-Clock.html#v:getCurrentTime https://hackage.haskell.org/package/time-1.12.2/docs/Data-Ti... [3]: https://hackage.haskell.org/package/base-4.18.0.0/docs/Control-Concurrent-MVar.html https://hackage.haskell.org/package/base-4.18.0.0/docs/Contr... [4]: https://hackage.haskell.org/package/stm-2.5.1.0/docs/Control-Concurrent-STM-TMVar.html https://hackage.haskell.org/package/stm-2.5.1.0/docs/Control... [5]: https://hackage.haskell.org/package/aeson-2.2.0.0/docs/Data-Aeson.html https://hackage.haskell.org/package/aeson-2.2.0.0/docs/Data-... [6]: https://hackage.haskell.org/package/warp-3.3.28/docs/Network-Wai-Handler-Warp.html#v:setInstallShutdownHandler https://hackage.haskell.org/package/warp-3.3.28/docs/Network...
- draven 3y agoI don't have time to try it atm but this looks like it would be quite easy to implement in Clojure (that falls under "Lisp", right?)
- tlavoie 3y agoThere are bunches of web frameworks and various support libraries for both Haskell and for Common Lisp. They'll range from simple use cases to more complete and/or opinionated in style, depending what your needs are. For Haskell examples, Servant is used for web APIs, where Yesod is a larger all-around framework. https://www.servant.dev/ https://www.servant.dev/ https://www.yesodweb.com/ https://www.yesodweb.com/