Skip to content

Latest commit

 

History

History
126 lines (87 loc) · 3.48 KB

process.rst

File metadata and controls

126 lines (87 loc) · 3.48 KB

Process (spawn_link)

Using gen servers for absolutely everything is very much overkill, quite often we just want to spin up a child process via spawn or spawn_link, and then communicate with it by sending it messages directly. This can be useful when performing longer tasks as part of a gen server for example but not wanting to block the execution of that gen server

We'll build up that as the example here because it's such a common pattern.

Spinning up a child process

The bare minimum to spin up a child process is

  • Define the type of message it will expect to receive
  • Define a function that will operate within the context of the newly spawned child process (the ProcessM Monad)
data ChildMsg = Tick

childProcess :: ProcessM ChildMsg Unit
childProcess = pure unit

init :: Effect Unit
init = do
  _ <- Process.spawnLink childProcess

Now in this example, the process will start up and then immediately terminate because we don't do anything in the function invoked as part of spawnLink - we did say the bare minimum required..

We can change this to wait for a message indefinitely and then exit by using the functions given to us in the ProcessM context.

data ChildMsg = Tick

childProcess :: ProcessM ChildMsg Unit
childProcess = do 
  msg <- receive
  case msg of
    Tick -> pure unit

init :: Effect Unit
init = do
  _ <- Process.spawnLink childProcess

Or indeed, wait for a message and then loop and wait for a message again

data ChildMsg 
  = Tick
  | Exit

childProcess :: ProcessM ChildMsg Unit
childProcess = do
  msg <- receive
  case msg of
    Tick -> do
      log "tick"
      childProcess 
    Exit -> pure unit

init :: Effect Unit
init = do
  _ <- Process.spawnLink childProcess

Note: an Exit value was added in this example, as some branch of the function has to return the expected type (unit), or the compiler will get upset.

So how we do we send this newly awakened process a message? We're presently discarding the result of spawnLink - which is of type Process ChildMsg, so we'll want that obviously.

data ChildMsg 
  = Tick
  | Exit

childProcess :: ProcessM ChildMsg Unit
childProcess = do
  msg <- receive
  case msg of
    Tick -> do
      log "tick"
      childProcess 
    Exit -> pure unit

init :: Effect Unit
init = do
  child <- Process.spawnLink childProcess
  child ! Tick

Next up we'll probably want to get a message back from our long running process, to do that we'll probably want to pass it a pid or a process - so let's move into the context of a GenServer and spin up a child process from there.

data ChildMsg 
  = Tick
  | Exit

data Msg 
  = Response

childProcess :: Process Msg -> ProcessM ChildMsg Unit
childProcess parent = do
  msg <- receive
  case msg of
    Tick -> do
      parent ! Response
      childProcess parent
    Exit -> pure unit

init :: InitFn Unit Unit Msg {}
init = do
  self <- self
  child <- Process.spawnLink $ childProcess self
  child ! Tick

handleInfo :: InfoFn Unit Unit Msg State
handleInfo msg state =
  case msg of 
    Response -> ...

And voila, now we have a gen server that starts a child process that when sent a 'Tick' message, responds to use with a 'Response' message and it's all type safe thanks to the wonders of Purescript.