GenServer

Client-Server Model

See: Erlang gen_server Behaviour

Client-server model

GenServer Typeclass

  1. class GenServer req rep st | req -> rep, rep -> st, st -> req where
  2. handleCall :: HandleCall req rep st
  3. handleCast :: HandleCast req rep st

Server Example

  1. module Demo.Server
  2. ( start
  3. , inc
  4. , dec
  5. , query
  6. ) where
  7. import Prelude
  8. import Control.Behaviour.GenServer
  9. ( class GenServer
  10. , HandleCall
  11. , HandleCast
  12. , Init
  13. , startLinkWith
  14. , initOk
  15. , call
  16. , cast
  17. , noReply
  18. , reply
  19. , shutdown
  20. )
  21. import System.IO (println)
  22. data Request = Inc | Dec | Query
  23. data Reply = QueryResult Integer
  24. data State = State Integer
  25. name :: Atom
  26. name = :server
  27. start :: Process Pid
  28. start = startLinkWith name (init 20)
  29. -----------------------------------------------------------------------------
  30. -- | Server API
  31. -----------------------------------------------------------------------------
  32. inc :: Process ()
  33. inc = cast name Inc
  34. dec :: Process ()
  35. dec = cast name Dec
  36. query :: Process Integer
  37. query = do
  38. QueryResult i <- call name Query
  39. return i
  40. -----------------------------------------------------------------------------
  41. -- | Server callbacks
  42. -----------------------------------------------------------------------------
  43. instance GenServer Request Reply State where
  44. handleCall = handleCall
  45. handleCast = handleCast
  46. init :: Integer -> Init Request State
  47. init n = initOk (State n)
  48. handleCall :: HandleCall Request Reply State
  49. handleCall Query _from (State i) = do
  50. println "Call: Query"
  51. reply (QueryResult i) (State i)
  52. handleCall _req _from st =
  53. shutdown :badRequest st
  54. handleCast :: HandleCast Request Reply State
  55. handleCast Inc (State n) = do
  56. println "Cast: Inc"
  57. noReply $ State (n+1)
  58. handleCast Dec (State n) = do
  59. println "Cast: Dec"
  60. noReply $ State (n-1)
  61. handleCast _ st = noReply st

Start a Server process

  1. -- | Start a standalone Server process.
  2. start :: forall req rep st. GenServer req rep st => (Init req st) -> Process Pid
  3. startWith :: forall req rep st. GenServer req rep st => Name -> (Init req st) -> Process Pid
  4. -- | Start a Server process as part of a supervision tree.
  5. startLink :: forall req rep st. GenServer req rep st => (Init req st) -> Process Pid
  6. startLinkWith :: forall req rep st. GenServer req rep st => Name -> (Init req st) -> Process Pid

Init callback

  1. -- | Init Result
  2. data InitResult req st
  3. = InitOk st (Maybe (Action req))
  4. -- ^ {ok, State}
  5. | InitIgnore
  6. -- ^ ignore
  7. | InitStop ExitReason
  8. -- ^ {stop, Reason}
  9. -- | Init callback
  10. type Init req st = Process (InitResult req st)

HandleCall and HandleCast

  1. -- | HandleCall callback
  2. type HandleCall req rep st
  3. = req -> From -> st -> Process (Reply req rep st)
  4. -- | HandleCast callback
  5. type HandleCast req rep st
  6. = req -> st -> Process (Reply req rep st)

Client APIs

  1. -- | Synchronous call to the server process.
  2. call :: forall req rep. Name -> req -> Process rep
  3. -- | Sends an asynchronous request to the server process.
  4. cast :: forall req. Name -> req -> Process ()