git.iko.soy/rowtype-yoga/purescript-yoga-fastify-om
on main help sign in
96 lines 2.8 kB history raw
1module Test.SharedState where
3import Prelude
5import Control.Monad.Reader.Trans (ask)
7import Effect (Effect)
8import Effect.Aff (Aff, launchAff_)
9import Effect.Class (liftEffect)
10import Effect.Class.Console as Console
11import Node.Path as Path
12import Node.Process as Process
13import Node.WorkerBees as WB
14import Node.WorkerBees.Aff.Pool as Pool
15import Yoga.Fastify.Fastify (Host(..), Port(..))
16import Yoga.Fastify.Fastify as F
17import Yoga.HTTP.API.Path (type (/), type (:))
18import Yoga.Fastify.Om.Route (GET, Route, Request, Handler, handle, respond, reject)
19import Yoga.Fastify.Om.API (registerAPI)
20import Yoga.Om as Om
21import Yoga.Om.WorkerBees.SharedInt as SharedInt
23-- Types
25type CounterInput = { n :: Int }
26type CounterOutput = { result :: Int, count :: Int }
28-- Routes
30type FibRoute = Route GET
31 ("fib" / "n" : Int)
32 (Request {})
33 ( ok :: { body :: { n :: Int, result :: Int, totalProcessed :: Int } }
34 , badRequest :: { body :: { error :: String } }
35 )
37type CountRoute = Route GET
38 "count"
39 (Request {})
40 ( ok :: { body :: { totalProcessed :: Int } }
41 )
43type API =
44 { fib :: FibRoute
45 , count :: CountRoute
46 }
48-- Handlers
50fibHandler :: Pool.WorkerPool CounterInput CounterOutput -> Handler FibRoute ()
51fibHandler pool = handle do
52 { path: { n } } <- ask
53 when (n < 0) do
54 reject @"badRequest" { error: "n must be non-negative" }
55 when (n > 40) do
56 reject @"badRequest" { error: "n must be <= 40" }
57 { result, count } <- Om.fromAff $ Pool.invoke pool { n }
58 respond @"ok" { n, result, totalProcessed: count }
60countHandler :: SharedInt.SharedInt -> Handler CountRoute ()
61countHandler counter = handle do
62 totalProcessed <- Om.fromAff $ liftEffect $ SharedInt.read counter
63 respond @"ok" { totalProcessed }
65-- Server
67startServer :: Aff Unit
68startServer = do
69 cwd <- liftEffect Process.cwd
70 let workerPath = Path.concat [ cwd, "dist", "workers", "CounterWorker.js" ]
72 -- Create shared counter visible to all workers
73 counter <- liftEffect $ SharedInt.new 0
74 Console.log "Created shared counter (initial: 0)"
76 -- Create worker pool, passing the shared counter as workerData
77 let worker = WB.unsafeWorkerFromPath workerPath
78 pool <- Pool.make worker (SharedInt.toSendable counter) 4
79 Console.log "Worker pool started (4 workers with shared counter)"
81 app <- liftEffect $ F.fastify {}
82 liftEffect $ registerAPI @API
83 { fib: fibHandler pool
84 , count: countHandler counter
85 }
86 app
88 let port = 3001
89 Console.log $ " curl http://localhost:" <> show port <> "/fib/30"
90 Console.log $ " curl http://localhost:" <> show port <> "/count"
92 address <- F.listen { port: Port port, host: Host "0.0.0.0" } app
93 Console.log $ "Listening on " <> address
95main :: Effect Unit
96main = launchAff_ startServer