packages feed

extensible-effects-concurrent 0.21.1 → 0.22.0

raw patch · 24 files changed

+647/−249 lines, 24 filesdep ~deepseqdep ~textPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: deepseq, text

API changes (from Hackage documentation)

- Control.Eff.Concurrent: [SP] :: SchedulerProxy q
- Control.Eff.Concurrent: [SchedulerProxy] :: SchedulerProxy q
- Control.Eff.Concurrent: [Scheduler] :: SchedulerProxy q
- Control.Eff.Concurrent: data SchedulerProxy :: [Type -> Type] -> Type
- Control.Eff.Concurrent: filterMessageLazy :: Typeable a => (a -> Bool) -> MessageSelector a
- Control.Eff.Concurrent: selectAnyMessageLazy :: MessageSelector Dynamic
- Control.Eff.Concurrent: selectDynamicMessageLazy :: (Dynamic -> Maybe a) -> MessageSelector a
- Control.Eff.Concurrent: selectMessageLazy :: Typeable t => MessageSelector t
- Control.Eff.Concurrent: selectMessageProxy :: forall proxy t. (NFData t, Typeable t) => proxy t -> MessageSelector t
- Control.Eff.Concurrent: selectMessageProxyLazy :: forall proxy t. Typeable t => proxy t -> MessageSelector t
- Control.Eff.Concurrent: selectMessageWithLazy :: Typeable a => (a -> Maybe b) -> MessageSelector b
- Control.Eff.Concurrent: thisSchedulerProxy :: Eff (Process r : r) (SchedulerProxy r)
- Control.Eff.Concurrent.Process: [SP] :: SchedulerProxy q
- Control.Eff.Concurrent.Process: [SchedulerProxy] :: SchedulerProxy q
- Control.Eff.Concurrent.Process: [Scheduler] :: SchedulerProxy q
- Control.Eff.Concurrent.Process: data SchedulerProxy :: [Type -> Type] -> Type
- Control.Eff.Concurrent.Process: filterMessageLazy :: Typeable a => (a -> Bool) -> MessageSelector a
- Control.Eff.Concurrent.Process: selectAnyMessageLazy :: MessageSelector Dynamic
- Control.Eff.Concurrent.Process: selectDynamicMessageLazy :: (Dynamic -> Maybe a) -> MessageSelector a
- Control.Eff.Concurrent.Process: selectMessageLazy :: Typeable t => MessageSelector t
- Control.Eff.Concurrent.Process: selectMessageProxy :: forall proxy t. (NFData t, Typeable t) => proxy t -> MessageSelector t
- Control.Eff.Concurrent.Process: selectMessageProxyLazy :: forall proxy t. Typeable t => proxy t -> MessageSelector t
- Control.Eff.Concurrent.Process: selectMessageWithLazy :: Typeable a => (a -> Maybe b) -> MessageSelector b
- Control.Eff.Concurrent.Process: thisSchedulerProxy :: Eff (Process r : r) (SchedulerProxy r)
+ Control.Eff.Concurrent: [ProcessTimeout] :: String -> ExitReason 'Recoverable
+ Control.Eff.Concurrent: callWithTimeout :: forall result api r q. (SetMember Process (Process q) r, Member Interrupts r, Typeable api, Typeable (Api api ( 'Synchronous result)), NFData (Api api ( 'Synchronous result)), Typeable result, NFData result, Show result, Member Logs r, Lifted IO q, Lifted IO r, HasCallStack) => Server api -> Api api ( 'Synchronous result) -> Timeout -> Eff r result
+ Control.Eff.Concurrent: cancelTimer :: forall r q. (Lifted IO q, HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => TimerReference -> Eff r ()
+ Control.Eff.Concurrent: data StrictDynamic
+ Control.Eff.Concurrent: fromStrictDynamic :: Typeable a => StrictDynamic -> Maybe a
+ Control.Eff.Concurrent: receiveSelectedWithMonitorAfter :: forall a r q. (Lifted IO q, HasCallStack, SetMember Process (Process q) r, Member Interrupts r, Show a) => ProcessId -> MessageSelector a -> Timeout -> Eff r (Either (Either ProcessDown TimerElapsed) a)
+ Control.Eff.Concurrent: selectAnyMessage :: MessageSelector StrictDynamic
+ Control.Eff.Concurrent: toStrictDynamic :: (Typeable a, NFData a) => a -> StrictDynamic
+ Control.Eff.Concurrent: unwrapStrictDynamic :: StrictDynamic -> Dynamic
+ Control.Eff.Concurrent.Api: instance forall k (api :: k). Control.DeepSeq.NFData (Control.Eff.Concurrent.Api.Server api)
+ Control.Eff.Concurrent.Api.Client: callWithTimeout :: forall result api r q. (SetMember Process (Process q) r, Member Interrupts r, Typeable api, Typeable (Api api ( 'Synchronous result)), NFData (Api api ( 'Synchronous result)), Typeable result, NFData result, Show result, Member Logs r, Lifted IO q, Lifted IO r, HasCallStack) => Server api -> Api api ( 'Synchronous result) -> Timeout -> Eff r result
+ Control.Eff.Concurrent.Api.GenServer: MkSomeMessage :: SomeMessage a
+ Control.Eff.Concurrent.Api.GenServer: class (Typeable (GenServerState a), NFData (GenServerState a)) => GenServer a eff where {
+ Control.Eff.Concurrent.Api.GenServer: data SomeMessage a
+ Control.Eff.Concurrent.Api.GenServer: genServerHandle :: (GenServer a eff, '[Interrupts, Logs] <:: eff, SetMember Process (Process q) eff) => Api a v -> Eff (State (GenServerState a) : eff) (ApiReply v)
+ Control.Eff.Concurrent.Api.GenServer: genServerInfoCommand :: GenServer a eff => Api a ( 'Synchronous Text)
+ Control.Eff.Concurrent.Api.GenServer: genServerInit :: (GenServer a eff, '[Interrupts, Logs] <:: eff, SetMember Process (Process q) eff) => a -> Eff eff (GenServerState a)
+ Control.Eff.Concurrent.Api.GenServer: genServerInterrupt :: (GenServer a eff, '[Interrupts, Logs] <:: eff, SetMember Process (Process q) eff) => InterruptReason -> Eff (State (GenServerState a) : eff) ()
+ Control.Eff.Concurrent.Api.GenServer: runGenServer :: forall q e h a. (GenServer a e, SetMember Process (Process q) e, Member Interrupts e, LogsTo h e) => a -> Eff e (Server a)
+ Control.Eff.Concurrent.Api.GenServer: type family ApiReply (s :: Synchronicity)
+ Control.Eff.Concurrent.Api.GenServer: }
+ Control.Eff.Concurrent.Api.Observer: instance Control.DeepSeq.NFData o => Control.DeepSeq.NFData (Control.Eff.Concurrent.Api.Api (Control.Eff.Concurrent.Api.Observer.Observer o) 'Control.Eff.Concurrent.Api.Asynchronous)
+ Control.Eff.Concurrent.Api.Observer: instance Control.DeepSeq.NFData o => Control.DeepSeq.NFData (Control.Eff.Concurrent.Api.Observer.Observer o)
+ Control.Eff.Concurrent.Api.Observer: instance forall k (o :: k) (r :: Control.Eff.Concurrent.Api.Synchronicity). Control.DeepSeq.NFData (Control.Eff.Concurrent.Api.Api (Control.Eff.Concurrent.Api.Observer.ObserverRegistry o) r)
+ Control.Eff.Concurrent.Process: [ProcessTimeout] :: String -> ExitReason 'Recoverable
+ Control.Eff.Concurrent.Process: data StrictDynamic
+ Control.Eff.Concurrent.Process: fromStrictDynamic :: Typeable a => StrictDynamic -> Maybe a
+ Control.Eff.Concurrent.Process: instance GHC.Show.Show Control.Eff.Concurrent.Process.StrictDynamic
+ Control.Eff.Concurrent.Process: selectAnyMessage :: MessageSelector StrictDynamic
+ Control.Eff.Concurrent.Process: toStrictDynamic :: (Typeable a, NFData a) => a -> StrictDynamic
+ Control.Eff.Concurrent.Process: unwrapStrictDynamic :: StrictDynamic -> Dynamic
+ Control.Eff.Concurrent.Process.Timer: receiveSelectedWithMonitorAfter :: forall a r q. (Lifted IO q, HasCallStack, SetMember Process (Process q) r, Member Interrupts r, Show a) => ProcessId -> MessageSelector a -> Timeout -> Eff r (Either (Either ProcessDown TimerElapsed) a)
+ Control.Eff.Log.MessageRenderer: renderLogMessageBodyNoLocation :: LogMessageRenderer Text
+ Control.Eff.Log.MessageRenderer: renderRFC5424Header :: LogMessageRenderer Text
+ Control.Eff.Log.MessageRenderer: renderRFC5424NoLocation :: LogMessageRenderer Text
- Control.Eff.Concurrent: [Call] :: forall api reply. (Typeable api, Typeable reply, Typeable (Api api ( 'Synchronous reply))) => Int -> ProcessId -> Api api ( 'Synchronous reply) -> Request api
+ Control.Eff.Concurrent: [Call] :: forall api reply. (Typeable api, Typeable reply, NFData reply, Typeable (Api api ( 'Synchronous reply)), NFData (Api api ( 'Synchronous reply))) => Int -> ProcessId -> Api api ( 'Synchronous reply) -> Request api
- Control.Eff.Concurrent: [Cast] :: forall api. (Typeable api, Typeable (Api api 'Asynchronous)) => Api api 'Asynchronous -> Request api
+ Control.Eff.Concurrent: [Cast] :: forall api. (Typeable api, Typeable (Api api 'Asynchronous), NFData (Api api 'Asynchronous)) => Api api 'Asynchronous -> Request api
- Control.Eff.Concurrent: [FlushMessages] :: Process r (ResumeProcess [Dynamic])
+ Control.Eff.Concurrent: [FlushMessages] :: Process r (ResumeProcess [StrictDynamic])
- Control.Eff.Concurrent: [Observer] :: (Show (Server p), Typeable p, Typeable o) => (o -> Maybe (Api p 'Asynchronous)) -> Server p -> Observer o
+ Control.Eff.Concurrent: [Observer] :: (Show (Server p), Typeable p, Typeable o, NFData o, NFData (Api p 'Asynchronous)) => (o -> Maybe (Api p 'Asynchronous)) -> Server p -> Observer o
- Control.Eff.Concurrent: [Reply] :: (Typeable api, Typeable reply) => Proxy (Api api ( 'Synchronous reply)) -> Int -> reply -> Reply (Api api ( 'Synchronous reply))
+ Control.Eff.Concurrent: [Reply] :: (Typeable api, Typeable reply, NFData reply) => Proxy (Api api ( 'Synchronous reply)) -> Int -> reply -> Reply (Api api ( 'Synchronous reply))
- Control.Eff.Concurrent: [SendMessage] :: ProcessId -> Dynamic -> Process r (ResumeProcess ())
+ Control.Eff.Concurrent: [SendMessage] :: ProcessId -> StrictDynamic -> Process r (ResumeProcess ())
- Control.Eff.Concurrent: call :: forall result api r q. (SetMember Process (Process q) r, Member Interrupts r, Typeable api, Typeable (Api api ( 'Synchronous result)), Typeable result, HasCallStack, NFData result, Show result) => Server api -> Api api ( 'Synchronous result) -> Eff r result
+ Control.Eff.Concurrent: call :: forall result api r q. (SetMember Process (Process q) r, Member Interrupts r, Typeable api, Typeable (Api api ( 'Synchronous result)), NFData (Api api ( 'Synchronous result)), Typeable result, NFData result, Show result, HasCallStack) => Server api -> Api api ( 'Synchronous result) -> Eff r result
- Control.Eff.Concurrent: callRegistered :: (Typeable reply, ServesApi o r q, HasCallStack, NFData reply, Show reply, Member Interrupts r) => Api o ( 'Synchronous reply) -> Eff r reply
+ Control.Eff.Concurrent: callRegistered :: (Typeable reply, ServesApi o r q, HasCallStack, NFData reply, Show reply, NFData (Api o ( 'Synchronous reply)), Member Interrupts r) => Api o ( 'Synchronous reply) -> Eff r reply
- Control.Eff.Concurrent: cast :: forall r q o. (HasCallStack, SetMember Process (Process q) r, Member Interrupts r, Typeable o, Typeable (Api o 'Asynchronous)) => Server o -> Api o 'Asynchronous -> Eff r ()
+ Control.Eff.Concurrent: cast :: forall r q o. (HasCallStack, SetMember Process (Process q) r, Member Interrupts r, Typeable o, Typeable (Api o 'Asynchronous), NFData (Api o 'Asynchronous)) => Server o -> Api o 'Asynchronous -> Eff r ()
- Control.Eff.Concurrent: castRegistered :: (Typeable o, ServesApi o r q, HasCallStack, Member Interrupts r) => Api o 'Asynchronous -> Eff r ()
+ Control.Eff.Concurrent: castRegistered :: (Typeable o, ServesApi o r q, HasCallStack, Member Interrupts r, NFData (Api o 'Asynchronous)) => Api o 'Asynchronous -> Eff r ()
- Control.Eff.Concurrent: filterMessage :: (Typeable a, NFData a) => (a -> Bool) -> MessageSelector a
+ Control.Eff.Concurrent: filterMessage :: Typeable a => (a -> Bool) -> MessageSelector a
- Control.Eff.Concurrent: flushMessages :: forall r q. (HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => Eff r [Dynamic]
+ Control.Eff.Concurrent: flushMessages :: forall r q. (HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => Eff r [StrictDynamic]
- Control.Eff.Concurrent: forgetObserver :: (SetMember Process (Process q) r, HasCallStack, Member Interrupts r, Typeable o) => Observer o -> Server (ObserverRegistry o) -> Eff r ()
+ Control.Eff.Concurrent: forgetObserver :: (SetMember Process (Process q) r, HasCallStack, Member Interrupts r, Typeable o, NFData o) => Observer o -> Server (ObserverRegistry o) -> Eff r ()
- Control.Eff.Concurrent: fromServer :: forall api_aTEM api_aTOc. Iso (Server api_aTEM) (Server api_aTOc) ProcessId ProcessId
+ Control.Eff.Concurrent: fromServer :: forall api_aUbJ api_aUlU. Iso (Server api_aUbJ) (Server api_aUlU) ProcessId ProcessId
- Control.Eff.Concurrent: handleAnyMessages :: forall eff. HasCallStack => (Dynamic -> Eff eff CallbackResult) -> MessageCallback '[] eff
+ Control.Eff.Concurrent: handleAnyMessages :: forall eff. HasCallStack => (StrictDynamic -> Eff eff CallbackResult) -> MessageCallback '[] eff
- Control.Eff.Concurrent: handleCalls :: forall api eff effScheduler. (HasCallStack, Typeable api, SetMember Process (Process effScheduler) eff, Member Interrupts eff) => (forall secret reply. (Typeable reply, Typeable (Api api ( 'Synchronous reply))) => Api api ( 'Synchronous reply) -> (Eff eff (Maybe reply, CallbackResult) -> secret) -> secret) -> MessageCallback api eff
+ Control.Eff.Concurrent: handleCalls :: forall api eff effScheduler. (HasCallStack, Typeable api, SetMember Process (Process effScheduler) eff, Member Interrupts eff) => (forall secret reply. (NFData reply, Typeable reply, Typeable (Api api ( 'Synchronous reply))) => Api api ( 'Synchronous reply) -> (Eff eff (Maybe reply, CallbackResult) -> secret) -> secret) -> MessageCallback api eff
- Control.Eff.Concurrent: handleCallsDeferred :: forall api eff effScheduler. (HasCallStack, Typeable api, SetMember Process (Process effScheduler) eff, Member Interrupts eff) => (forall reply. (Typeable reply, Typeable (Api api ( 'Synchronous reply))) => RequestOrigin (Api api ( 'Synchronous reply)) -> Api api ( 'Synchronous reply) -> Eff eff CallbackResult) -> MessageCallback api eff
+ Control.Eff.Concurrent: handleCallsDeferred :: forall api eff effScheduler. (HasCallStack, Typeable api, SetMember Process (Process effScheduler) eff, Member Interrupts eff) => (forall reply. (Typeable reply, NFData reply, Typeable (Api api ( 'Synchronous reply))) => RequestOrigin (Api api ( 'Synchronous reply)) -> Api api ( 'Synchronous reply) -> Eff eff CallbackResult) -> MessageCallback api eff
- Control.Eff.Concurrent: handleCasts :: forall api eff. (HasCallStack, Typeable api, Typeable (Api api 'Asynchronous)) => (Api api 'Asynchronous -> Eff eff CallbackResult) -> MessageCallback api eff
+ Control.Eff.Concurrent: handleCasts :: forall api eff. (HasCallStack, Typeable api, Typeable (Api api 'Asynchronous), NFData (Request api)) => (Api api 'Asynchronous -> Eff eff CallbackResult) -> MessageCallback api eff
- Control.Eff.Concurrent: handleCastsAndCalls :: forall api eff effScheduler. (HasCallStack, Typeable api, Typeable (Api api 'Asynchronous), SetMember Process (Process effScheduler) eff, Member Interrupts eff) => (Api api 'Asynchronous -> Eff eff CallbackResult) -> (forall secret reply. (Typeable reply, Typeable (Api api ( 'Synchronous reply))) => Api api ( 'Synchronous reply) -> (Eff eff (Maybe reply, CallbackResult) -> secret) -> secret) -> MessageCallback api eff
+ Control.Eff.Concurrent: handleCastsAndCalls :: forall api eff effScheduler. (HasCallStack, Typeable api, Typeable (Api api 'Asynchronous), NFData (Request api), SetMember Process (Process effScheduler) eff, Member Interrupts eff) => (Api api 'Asynchronous -> Eff eff CallbackResult) -> (forall secret reply. (Typeable reply, Typeable (Api api ( 'Synchronous reply)), NFData reply) => Api api ( 'Synchronous reply) -> (Eff eff (Maybe reply, CallbackResult) -> secret) -> secret) -> MessageCallback api eff
- Control.Eff.Concurrent: handleObservations :: (HasCallStack, Typeable o, SetMember Process (Process q) r) => (o -> Eff r CallbackResult) -> MessageCallback (Observer o) r
+ Control.Eff.Concurrent: handleObservations :: (HasCallStack, Typeable o, SetMember Process (Process q) r, NFData (Observer o)) => (o -> Eff r CallbackResult) -> MessageCallback (Observer o) r
- Control.Eff.Concurrent: handleObserverRegistration :: forall o q r. (HasCallStack, Typeable o, SetMember Process (Process q) r, Member (ObserverState o) r) => MessageCallback (ObserverRegistry o) r
+ Control.Eff.Concurrent: handleObserverRegistration :: forall o q r. (HasCallStack, Typeable o, SetMember Process (Process q) r, Member (ObserverState o) r, Member Logs r) => MessageCallback (ObserverRegistry o) r
- Control.Eff.Concurrent: receiveAnyLoop :: forall r q endOfLoopResult. (SetMember Process (Process q) r, HasCallStack) => (Either InterruptReason Dynamic -> Eff r (Maybe endOfLoopResult)) -> Eff r endOfLoopResult
+ Control.Eff.Concurrent: receiveAnyLoop :: forall r q endOfLoopResult. (SetMember Process (Process q) r, HasCallStack) => (Either InterruptReason StrictDynamic -> Eff r (Maybe endOfLoopResult)) -> Eff r endOfLoopResult
- Control.Eff.Concurrent: receiveAnyMessage :: forall r q. (HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => Eff r Dynamic
+ Control.Eff.Concurrent: receiveAnyMessage :: forall r q. (HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => Eff r StrictDynamic
- Control.Eff.Concurrent: receiveLoop :: forall r q a endOfLoopResult. (SetMember Process (Process q) r, HasCallStack, Typeable a) => (Either InterruptReason a -> Eff r (Maybe endOfLoopResult)) -> Eff r endOfLoopResult
+ Control.Eff.Concurrent: receiveLoop :: forall r q a endOfLoopResult. (SetMember Process (Process q) r, HasCallStack, NFData a, Typeable a) => (Either InterruptReason a -> Eff r (Maybe endOfLoopResult)) -> Eff r endOfLoopResult
- Control.Eff.Concurrent: receiveMessage :: forall a r q. (HasCallStack, Typeable a, Show a, SetMember Process (Process q) r, Member Interrupts r) => Eff r a
+ Control.Eff.Concurrent: receiveMessage :: forall a r q. (HasCallStack, Typeable a, NFData a, Show a, SetMember Process (Process q) r, Member Interrupts r) => Eff r a
- Control.Eff.Concurrent: registerObserver :: (SetMember Process (Process q) r, HasCallStack, Member Interrupts r, Typeable o) => Observer o -> Server (ObserverRegistry o) -> Eff r ()
+ Control.Eff.Concurrent: registerObserver :: (SetMember Process (Process q) r, HasCallStack, Member Interrupts r, Typeable o, NFData o) => Observer o -> Server (ObserverRegistry o) -> Eff r ()
- Control.Eff.Concurrent: selectDynamicMessage :: NFData a => (Dynamic -> Maybe a) -> MessageSelector a
+ Control.Eff.Concurrent: selectDynamicMessage :: (StrictDynamic -> Maybe a) -> MessageSelector a
- Control.Eff.Concurrent: selectMessage :: (NFData t, Typeable t) => MessageSelector t
+ Control.Eff.Concurrent: selectMessage :: Typeable t => MessageSelector t
- Control.Eff.Concurrent: selectMessageWith :: (Typeable a, NFData b) => (a -> Maybe b) -> MessageSelector b
+ Control.Eff.Concurrent: selectMessageWith :: Typeable a => (a -> Maybe b) -> MessageSelector b
- Control.Eff.Concurrent: sendAnyMessage :: forall r q. (SetMember Process (Process q) r, HasCallStack, Member Interrupts r) => ProcessId -> Dynamic -> Eff r ()
+ Control.Eff.Concurrent: sendAnyMessage :: forall r q. (SetMember Process (Process q) r, HasCallStack, Member Interrupts r) => ProcessId -> StrictDynamic -> Eff r ()
- Control.Eff.Concurrent: sendMessage :: forall r q o. (SetMember Process (Process q) r, HasCallStack, Member Interrupts r, Typeable o) => ProcessId -> o -> Eff r ()
+ Control.Eff.Concurrent: sendMessage :: forall r q o. (SetMember Process (Process q) r, HasCallStack, Member Interrupts r, Typeable o, NFData o) => ProcessId -> o -> Eff r ()
- Control.Eff.Concurrent: sendReply :: forall request reply api eff q. (SetMember Process (Process q) eff, Member Interrupts eff, Typeable api, ApiType request ~ api, ReplyType request ~ reply, request ~ Api api ( 'Synchronous reply), Typeable reply) => RequestOrigin request -> reply -> Eff eff ()
+ Control.Eff.Concurrent: sendReply :: forall request reply api eff q. (SetMember Process (Process q) eff, Member Interrupts eff, Typeable api, ApiType request ~ api, ReplyType request ~ reply, request ~ Api api ( 'Synchronous reply), Typeable reply, NFData reply) => RequestOrigin request -> reply -> Eff eff ()
- Control.Eff.Concurrent: spawnApiServerStateful :: forall api eff state. (HasCallStack, ToServerPids api) => Eff (InterruptableProcess eff) state -> MessageCallback api (State state : InterruptableProcess eff) -> InterruptCallback (State state : ConsProcess eff) -> Eff (InterruptableProcess eff) (ServerPids api)
+ Control.Eff.Concurrent: spawnApiServerStateful :: forall api eff state. (HasCallStack, ToServerPids api, NFData state) => Eff (InterruptableProcess eff) state -> MessageCallback api (State state : InterruptableProcess eff) -> InterruptCallback (State state : ConsProcess eff) -> Eff (InterruptableProcess eff) (ServerPids api)
- Control.Eff.Concurrent: spawnLinkObservationQueueWriter :: forall o q. (Typeable o, Show o, Member Logs q, Lifted IO q, HasCallStack) => ObservationQueue o -> Eff (InterruptableProcess q) (Observer o)
+ Control.Eff.Concurrent: spawnLinkObservationQueueWriter :: forall o q. (Typeable o, Show o, NFData o, NFData (Api (Observer o) 'Asynchronous), Member Logs q, Lifted IO q, HasCallStack) => ObservationQueue o -> Eff (InterruptableProcess q) (Observer o)
- Control.Eff.Concurrent: toObserver :: Typeable o => Server (Observer o) -> Observer o
+ Control.Eff.Concurrent: toObserver :: (NFData o, Typeable o, NFData (Api (Observer o) 'Asynchronous)) => Server (Observer o) -> Observer o
- Control.Eff.Concurrent: toObserverFor :: (Typeable a, Typeable o) => (o -> Api a 'Asynchronous) -> Server a -> Observer o
+ Control.Eff.Concurrent: toObserverFor :: (Typeable a, NFData (Api a 'Asynchronous), Typeable o, NFData o) => (o -> Api a 'Asynchronous) -> Server a -> Observer o
- Control.Eff.Concurrent.Api: fromServer :: forall api_aTEM api_aTOc. Iso (Server api_aTEM) (Server api_aTOc) ProcessId ProcessId
+ Control.Eff.Concurrent.Api: fromServer :: forall api_aUbJ api_aUlU. Iso (Server api_aUbJ) (Server api_aUlU) ProcessId ProcessId
- Control.Eff.Concurrent.Api.Client: call :: forall result api r q. (SetMember Process (Process q) r, Member Interrupts r, Typeable api, Typeable (Api api ( 'Synchronous result)), Typeable result, HasCallStack, NFData result, Show result) => Server api -> Api api ( 'Synchronous result) -> Eff r result
+ Control.Eff.Concurrent.Api.Client: call :: forall result api r q. (SetMember Process (Process q) r, Member Interrupts r, Typeable api, Typeable (Api api ( 'Synchronous result)), NFData (Api api ( 'Synchronous result)), Typeable result, NFData result, Show result, HasCallStack) => Server api -> Api api ( 'Synchronous result) -> Eff r result
- Control.Eff.Concurrent.Api.Client: callRegistered :: (Typeable reply, ServesApi o r q, HasCallStack, NFData reply, Show reply, Member Interrupts r) => Api o ( 'Synchronous reply) -> Eff r reply
+ Control.Eff.Concurrent.Api.Client: callRegistered :: (Typeable reply, ServesApi o r q, HasCallStack, NFData reply, Show reply, NFData (Api o ( 'Synchronous reply)), Member Interrupts r) => Api o ( 'Synchronous reply) -> Eff r reply
- Control.Eff.Concurrent.Api.Client: cast :: forall r q o. (HasCallStack, SetMember Process (Process q) r, Member Interrupts r, Typeable o, Typeable (Api o 'Asynchronous)) => Server o -> Api o 'Asynchronous -> Eff r ()
+ Control.Eff.Concurrent.Api.Client: cast :: forall r q o. (HasCallStack, SetMember Process (Process q) r, Member Interrupts r, Typeable o, Typeable (Api o 'Asynchronous), NFData (Api o 'Asynchronous)) => Server o -> Api o 'Asynchronous -> Eff r ()
- Control.Eff.Concurrent.Api.Client: castRegistered :: (Typeable o, ServesApi o r q, HasCallStack, Member Interrupts r) => Api o 'Asynchronous -> Eff r ()
+ Control.Eff.Concurrent.Api.Client: castRegistered :: (Typeable o, ServesApi o r q, HasCallStack, Member Interrupts r, NFData (Api o 'Asynchronous)) => Api o 'Asynchronous -> Eff r ()
- Control.Eff.Concurrent.Api.Observer: [Observer] :: (Show (Server p), Typeable p, Typeable o) => (o -> Maybe (Api p 'Asynchronous)) -> Server p -> Observer o
+ Control.Eff.Concurrent.Api.Observer: [Observer] :: (Show (Server p), Typeable p, Typeable o, NFData o, NFData (Api p 'Asynchronous)) => (o -> Maybe (Api p 'Asynchronous)) -> Server p -> Observer o
- Control.Eff.Concurrent.Api.Observer: forgetObserver :: (SetMember Process (Process q) r, HasCallStack, Member Interrupts r, Typeable o) => Observer o -> Server (ObserverRegistry o) -> Eff r ()
+ Control.Eff.Concurrent.Api.Observer: forgetObserver :: (SetMember Process (Process q) r, HasCallStack, Member Interrupts r, Typeable o, NFData o) => Observer o -> Server (ObserverRegistry o) -> Eff r ()
- Control.Eff.Concurrent.Api.Observer: handleObservations :: (HasCallStack, Typeable o, SetMember Process (Process q) r) => (o -> Eff r CallbackResult) -> MessageCallback (Observer o) r
+ Control.Eff.Concurrent.Api.Observer: handleObservations :: (HasCallStack, Typeable o, SetMember Process (Process q) r, NFData (Observer o)) => (o -> Eff r CallbackResult) -> MessageCallback (Observer o) r
- Control.Eff.Concurrent.Api.Observer: handleObserverRegistration :: forall o q r. (HasCallStack, Typeable o, SetMember Process (Process q) r, Member (ObserverState o) r) => MessageCallback (ObserverRegistry o) r
+ Control.Eff.Concurrent.Api.Observer: handleObserverRegistration :: forall o q r. (HasCallStack, Typeable o, SetMember Process (Process q) r, Member (ObserverState o) r, Member Logs r) => MessageCallback (ObserverRegistry o) r
- Control.Eff.Concurrent.Api.Observer: registerObserver :: (SetMember Process (Process q) r, HasCallStack, Member Interrupts r, Typeable o) => Observer o -> Server (ObserverRegistry o) -> Eff r ()
+ Control.Eff.Concurrent.Api.Observer: registerObserver :: (SetMember Process (Process q) r, HasCallStack, Member Interrupts r, Typeable o, NFData o) => Observer o -> Server (ObserverRegistry o) -> Eff r ()
- Control.Eff.Concurrent.Api.Observer: toObserver :: Typeable o => Server (Observer o) -> Observer o
+ Control.Eff.Concurrent.Api.Observer: toObserver :: (NFData o, Typeable o, NFData (Api (Observer o) 'Asynchronous)) => Server (Observer o) -> Observer o
- Control.Eff.Concurrent.Api.Observer: toObserverFor :: (Typeable a, Typeable o) => (o -> Api a 'Asynchronous) -> Server a -> Observer o
+ Control.Eff.Concurrent.Api.Observer: toObserverFor :: (Typeable a, NFData (Api a 'Asynchronous), Typeable o, NFData o) => (o -> Api a 'Asynchronous) -> Server a -> Observer o
- Control.Eff.Concurrent.Api.Observer.Queue: spawnLinkObservationQueueWriter :: forall o q. (Typeable o, Show o, Member Logs q, Lifted IO q, HasCallStack) => ObservationQueue o -> Eff (InterruptableProcess q) (Observer o)
+ Control.Eff.Concurrent.Api.Observer.Queue: spawnLinkObservationQueueWriter :: forall o q. (Typeable o, Show o, NFData o, NFData (Api (Observer o) 'Asynchronous), Member Logs q, Lifted IO q, HasCallStack) => ObservationQueue o -> Eff (InterruptableProcess q) (Observer o)
- Control.Eff.Concurrent.Api.Server: handleAnyMessages :: forall eff. HasCallStack => (Dynamic -> Eff eff CallbackResult) -> MessageCallback '[] eff
+ Control.Eff.Concurrent.Api.Server: handleAnyMessages :: forall eff. HasCallStack => (StrictDynamic -> Eff eff CallbackResult) -> MessageCallback '[] eff
- Control.Eff.Concurrent.Api.Server: handleCalls :: forall api eff effScheduler. (HasCallStack, Typeable api, SetMember Process (Process effScheduler) eff, Member Interrupts eff) => (forall secret reply. (Typeable reply, Typeable (Api api ( 'Synchronous reply))) => Api api ( 'Synchronous reply) -> (Eff eff (Maybe reply, CallbackResult) -> secret) -> secret) -> MessageCallback api eff
+ Control.Eff.Concurrent.Api.Server: handleCalls :: forall api eff effScheduler. (HasCallStack, Typeable api, SetMember Process (Process effScheduler) eff, Member Interrupts eff) => (forall secret reply. (NFData reply, Typeable reply, Typeable (Api api ( 'Synchronous reply))) => Api api ( 'Synchronous reply) -> (Eff eff (Maybe reply, CallbackResult) -> secret) -> secret) -> MessageCallback api eff
- Control.Eff.Concurrent.Api.Server: handleCallsDeferred :: forall api eff effScheduler. (HasCallStack, Typeable api, SetMember Process (Process effScheduler) eff, Member Interrupts eff) => (forall reply. (Typeable reply, Typeable (Api api ( 'Synchronous reply))) => RequestOrigin (Api api ( 'Synchronous reply)) -> Api api ( 'Synchronous reply) -> Eff eff CallbackResult) -> MessageCallback api eff
+ Control.Eff.Concurrent.Api.Server: handleCallsDeferred :: forall api eff effScheduler. (HasCallStack, Typeable api, SetMember Process (Process effScheduler) eff, Member Interrupts eff) => (forall reply. (Typeable reply, NFData reply, Typeable (Api api ( 'Synchronous reply))) => RequestOrigin (Api api ( 'Synchronous reply)) -> Api api ( 'Synchronous reply) -> Eff eff CallbackResult) -> MessageCallback api eff
- Control.Eff.Concurrent.Api.Server: handleCasts :: forall api eff. (HasCallStack, Typeable api, Typeable (Api api 'Asynchronous)) => (Api api 'Asynchronous -> Eff eff CallbackResult) -> MessageCallback api eff
+ Control.Eff.Concurrent.Api.Server: handleCasts :: forall api eff. (HasCallStack, Typeable api, Typeable (Api api 'Asynchronous), NFData (Request api)) => (Api api 'Asynchronous -> Eff eff CallbackResult) -> MessageCallback api eff
- Control.Eff.Concurrent.Api.Server: handleCastsAndCalls :: forall api eff effScheduler. (HasCallStack, Typeable api, Typeable (Api api 'Asynchronous), SetMember Process (Process effScheduler) eff, Member Interrupts eff) => (Api api 'Asynchronous -> Eff eff CallbackResult) -> (forall secret reply. (Typeable reply, Typeable (Api api ( 'Synchronous reply))) => Api api ( 'Synchronous reply) -> (Eff eff (Maybe reply, CallbackResult) -> secret) -> secret) -> MessageCallback api eff
+ Control.Eff.Concurrent.Api.Server: handleCastsAndCalls :: forall api eff effScheduler. (HasCallStack, Typeable api, Typeable (Api api 'Asynchronous), NFData (Request api), SetMember Process (Process effScheduler) eff, Member Interrupts eff) => (Api api 'Asynchronous -> Eff eff CallbackResult) -> (forall secret reply. (Typeable reply, Typeable (Api api ( 'Synchronous reply)), NFData reply) => Api api ( 'Synchronous reply) -> (Eff eff (Maybe reply, CallbackResult) -> secret) -> secret) -> MessageCallback api eff
- Control.Eff.Concurrent.Api.Server: spawnApiServerStateful :: forall api eff state. (HasCallStack, ToServerPids api) => Eff (InterruptableProcess eff) state -> MessageCallback api (State state : InterruptableProcess eff) -> InterruptCallback (State state : ConsProcess eff) -> Eff (InterruptableProcess eff) (ServerPids api)
+ Control.Eff.Concurrent.Api.Server: spawnApiServerStateful :: forall api eff state. (HasCallStack, ToServerPids api, NFData state) => Eff (InterruptableProcess eff) state -> MessageCallback api (State state : InterruptableProcess eff) -> InterruptCallback (State state : ConsProcess eff) -> Eff (InterruptableProcess eff) (ServerPids api)
- Control.Eff.Concurrent.Process: [FlushMessages] :: Process r (ResumeProcess [Dynamic])
+ Control.Eff.Concurrent.Process: [FlushMessages] :: Process r (ResumeProcess [StrictDynamic])
- Control.Eff.Concurrent.Process: [SendMessage] :: ProcessId -> Dynamic -> Process r (ResumeProcess ())
+ Control.Eff.Concurrent.Process: [SendMessage] :: ProcessId -> StrictDynamic -> Process r (ResumeProcess ())
- Control.Eff.Concurrent.Process: filterMessage :: (Typeable a, NFData a) => (a -> Bool) -> MessageSelector a
+ Control.Eff.Concurrent.Process: filterMessage :: Typeable a => (a -> Bool) -> MessageSelector a
- Control.Eff.Concurrent.Process: flushMessages :: forall r q. (HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => Eff r [Dynamic]
+ Control.Eff.Concurrent.Process: flushMessages :: forall r q. (HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => Eff r [StrictDynamic]
- Control.Eff.Concurrent.Process: receiveAnyLoop :: forall r q endOfLoopResult. (SetMember Process (Process q) r, HasCallStack) => (Either InterruptReason Dynamic -> Eff r (Maybe endOfLoopResult)) -> Eff r endOfLoopResult
+ Control.Eff.Concurrent.Process: receiveAnyLoop :: forall r q endOfLoopResult. (SetMember Process (Process q) r, HasCallStack) => (Either InterruptReason StrictDynamic -> Eff r (Maybe endOfLoopResult)) -> Eff r endOfLoopResult
- Control.Eff.Concurrent.Process: receiveAnyMessage :: forall r q. (HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => Eff r Dynamic
+ Control.Eff.Concurrent.Process: receiveAnyMessage :: forall r q. (HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => Eff r StrictDynamic
- Control.Eff.Concurrent.Process: receiveLoop :: forall r q a endOfLoopResult. (SetMember Process (Process q) r, HasCallStack, Typeable a) => (Either InterruptReason a -> Eff r (Maybe endOfLoopResult)) -> Eff r endOfLoopResult
+ Control.Eff.Concurrent.Process: receiveLoop :: forall r q a endOfLoopResult. (SetMember Process (Process q) r, HasCallStack, NFData a, Typeable a) => (Either InterruptReason a -> Eff r (Maybe endOfLoopResult)) -> Eff r endOfLoopResult
- Control.Eff.Concurrent.Process: receiveMessage :: forall a r q. (HasCallStack, Typeable a, Show a, SetMember Process (Process q) r, Member Interrupts r) => Eff r a
+ Control.Eff.Concurrent.Process: receiveMessage :: forall a r q. (HasCallStack, Typeable a, NFData a, Show a, SetMember Process (Process q) r, Member Interrupts r) => Eff r a
- Control.Eff.Concurrent.Process: selectDynamicMessage :: NFData a => (Dynamic -> Maybe a) -> MessageSelector a
+ Control.Eff.Concurrent.Process: selectDynamicMessage :: (StrictDynamic -> Maybe a) -> MessageSelector a
- Control.Eff.Concurrent.Process: selectMessage :: (NFData t, Typeable t) => MessageSelector t
+ Control.Eff.Concurrent.Process: selectMessage :: Typeable t => MessageSelector t
- Control.Eff.Concurrent.Process: selectMessageWith :: (Typeable a, NFData b) => (a -> Maybe b) -> MessageSelector b
+ Control.Eff.Concurrent.Process: selectMessageWith :: Typeable a => (a -> Maybe b) -> MessageSelector b
- Control.Eff.Concurrent.Process: sendAnyMessage :: forall r q. (SetMember Process (Process q) r, HasCallStack, Member Interrupts r) => ProcessId -> Dynamic -> Eff r ()
+ Control.Eff.Concurrent.Process: sendAnyMessage :: forall r q. (SetMember Process (Process q) r, HasCallStack, Member Interrupts r) => ProcessId -> StrictDynamic -> Eff r ()
- Control.Eff.Concurrent.Process: sendMessage :: forall r q o. (SetMember Process (Process q) r, HasCallStack, Member Interrupts r, Typeable o) => ProcessId -> o -> Eff r ()
+ Control.Eff.Concurrent.Process: sendMessage :: forall r q o. (SetMember Process (Process q) r, HasCallStack, Member Interrupts r, Typeable o, NFData o) => ProcessId -> o -> Eff r ()
- Control.Eff.Concurrent.Process.Interactive: submitCall :: forall o q r. (SetMember Lift (Lift IO) r, Typeable o, Typeable q, NFData q, Show q, Member Interrupts r) => SchedulerSession r -> Server o -> Api o ( 'Synchronous q) -> IO q
+ Control.Eff.Concurrent.Process.Interactive: submitCall :: forall o q r. (SetMember Lift (Lift IO) r, Typeable o, Typeable q, NFData q, Show q, Member Interrupts r, NFData (Api o ( 'Synchronous q))) => SchedulerSession r -> Server o -> Api o ( 'Synchronous q) -> IO q
- Control.Eff.Concurrent.Process.Interactive: submitCast :: forall o r. (SetMember Lift (Lift IO) r, Typeable o, Member Interrupts r) => SchedulerSession r -> Server o -> Api o 'Asynchronous -> IO ()
+ Control.Eff.Concurrent.Process.Interactive: submitCast :: forall o r. (SetMember Lift (Lift IO) r, Typeable o, NFData (Api o 'Asynchronous), Member Interrupts r) => SchedulerSession r -> Server o -> Api o 'Asynchronous -> IO ()
- Control.Eff.LogWriter.Async: withAsyncLogging :: (LogsTo IO e, Lifted IO e, MonadBaseControl IO (Eff e), Integral len) => LogWriter IO -> len -> Text -> Facility -> LogPredicate -> Eff (Logs : (LogWriterReader IO : e)) a -> Eff e a
+ Control.Eff.LogWriter.Async: withAsyncLogging :: (Lifted IO e, MonadBaseControl IO (Eff e), Integral len) => LogWriter IO -> len -> Text -> Facility -> LogPredicate -> Eff (Logs : (LogWriterReader IO : e)) a -> Eff e a

Files

ChangeLog.md view
@@ -1,5 +1,50 @@ # Changelog for extensible-effects-concurrent +## Plan for future 0.23.0++- Add `gen_server` behaviour clone:    +    - Disallow non-`Api`-messages+    - Add `Api AnyMsg 'Asynchronous` +    - Add `Api GetInfo ('Synchronous Text)`  +         +    - Every `Api` type instance now **must** be an `NFData` +      and a `ToLogText` instance+    - `call` will always require a `Timeout`+    - `call` now monitors the caller+    - `call` now monitors the called process+    - `call` now returns `Either TimeoutError a`   ++- Logging improvements:+    - Introduce `ToLogText`+    - Remove `ToLogMessage`+    - Remove `logXXX'` users have to use `logXXX` and `ToLogText` ++## 0.22.0    ++- Remove `SchedulerProxy` ruins ++- Make message sending strict:++  Ensure that every message sent from one process to another+  is reduced to normal form by the sender. ++    - Remove *all* lazy message selectors+    - Introduce a newtype wrapper `StrictDynamic` around `Dynamic`+      and export only a constructor that deeply evaluates the+      value to *rnf* before converting it to a `Dynamic` ++- Change the `Server` API for better system *vitality*:++- Add `callWithTimeout`: A `call` over `IO` with a `Timeout` parameter++- Add more efficient log renderer:+    - `renderLogMessageBodyNoLocation`+    - `renderRFC5424NoLocation`     +          +## 0.21.2++- Fix copy-paste error: Remove the `LogsTo` constraint from `withAsyncLogWriter`+ ## 0.21.1  - Remove dependency to the `socket` and `socket-unix` packages
examples/example-1/Main.hs view
@@ -8,6 +8,7 @@ import           Control.Eff.Concurrent import qualified Control.Exception             as Exc import qualified Data.Text as T+import           Control.DeepSeq  data TestApi   deriving Typeable@@ -18,6 +19,13 @@   Terminate :: Api TestApi ('Synchronous ())   TerminateError :: String -> Api TestApi ('Synchronous ())   deriving (Typeable)++instance NFData (Api TestApi x) where+  rnf (SayHello s) = rnf s+  rnf (Shout s) = rnf s+  rnf Terminate = ()+  rnf (TerminateError s) = rnf s+  data MyException = MyException     deriving Show
examples/example-2/Main.hs view
@@ -8,6 +8,7 @@ import           Control.Monad import           Data.Foldable import           Control.Concurrent+import           Control.DeepSeq  main :: IO () main = defaultMain (void counterExample)@@ -21,6 +22,10 @@   Cnt :: Api Counter ('Synchronous Integer)   deriving Typeable +instance NFData (Api Counter x) where+  rnf Inc = ()+  rnf Cnt = ()+ counterExample   :: (Member Logs q, Lifted IO q)   => Eff (InterruptableProcess q) ()@@ -57,8 +62,11 @@   Whoopediedoo :: Bool -> Api SupiDupi ('Synchronous (Maybe ()))   deriving Typeable -data CounterChanged = CounterChanged Integer-  deriving (Show, Typeable)+instance NFData (Api SupiDupi r) where+  rnf (Whoopediedoo b) = rnf b++newtype CounterChanged = CounterChanged Integer+  deriving (Show, Typeable, NFData)  spawnCounter   :: (Member Logs q)
extensible-effects-concurrent.cabal view
@@ -1,6 +1,6 @@ cabal-version:  2.0 name:           extensible-effects-concurrent-version:        0.21.1+version:        0.22.0 description:    Please see the README on GitHub at <https://github.com/sheyll/extensible-effects-concurrent#readme> synopsis:       Message passing concurrency as extensible-effect homepage:       https://github.com/sheyll/extensible-effects-concurrent#readme@@ -83,6 +83,7 @@                   Control.Eff.Concurrent.Api,                   Control.Eff.Concurrent.Api.Client,                   Control.Eff.Concurrent.Api.Server,+                  Control.Eff.Concurrent.Api.GenServer,                   Control.Eff.Concurrent.Process,                   Control.Eff.Concurrent.Process.Timer,                   Control.Eff.Concurrent.Process.ForkIOScheduler,@@ -134,11 +135,13 @@               , extensible-effects               , lens               , text+              , deepseq   ghc-options: -Wall -threaded -fno-full-laziness   default-language: Haskell2010   default-extensions:   AllowAmbiguousTypes                       , BangPatterns                       , DataKinds+                      , DeriveGeneric                       , FlexibleContexts                       , FlexibleInstances                       , FunctionalDependencies@@ -164,6 +167,7 @@               , extensible-effects               , lens               , text+              , deepseq   ghc-options: -Wall -threaded -fno-full-laziness   default-language: Haskell2010   default-extensions:   AllowAmbiguousTypes@@ -225,6 +229,7 @@               , extensible-effects               , deepseq               , text+              , deepseq   ghc-options: -Wall -threaded -fno-full-laziness   default-language: Haskell2010   default-extensions:   AllowAmbiguousTypes@@ -255,22 +260,24 @@               , ForkIOScheduler               , Interactive               , LoggingTests+              , LogMessageIdeaTest               , LoopTests               , ProcessBehaviourTestCases+              , ServerForkIO               , SingleThreadedScheduler-              , LogMessageIdeaTest   ghc-options: -Wall -threaded -fno-full-laziness   build-depends:                 async               , base               , data-default+              , deepseq               , extensible-effects-concurrent               , extensible-effects               , tasty               , tasty-discover               , tasty-hunit+              , text               , containers-              , deepseq               , QuickCheck               , lens               , HUnit
src/Control/Eff/Concurrent.hs view
@@ -68,12 +68,14 @@ where  import           Control.Eff.Concurrent.Process ( Process(..)+                                                , StrictDynamic()+                                                , toStrictDynamic+                                                , fromStrictDynamic+                                                , unwrapStrictDynamic                                                 , ProcessId(..)                                                 , fromProcessId                                                 , ConsProcess                                                 , ResumeProcess(..)-                                                , SchedulerProxy(..)-                                                , thisSchedulerProxy                                                 , ProcessState(..)                                                 , yieldProcess                                                 , sendMessage@@ -92,16 +94,14 @@                                                   ( runMessageSelector                                                   )                                                 , selectMessage-                                                , selectMessageLazy-                                                , selectMessageProxy-                                                , selectMessageProxyLazy+                                                , selectMessage                                                 , filterMessage-                                                , filterMessageLazy+                                                , filterMessage                                                 , selectMessageWith-                                                , selectMessageWithLazy+                                                , selectMessageWith                                                 , selectDynamicMessage-                                                , selectDynamicMessageLazy-                                                , selectAnyMessageLazy+                                                , selectDynamicMessage+                                                , selectAnyMessage                                                 , self                                                 , isProcessAlive                                                 , spawn@@ -156,8 +156,10 @@                                                 , sendAfter                                                 , startTimer                                                 , selectTimerElapsed+                                                , cancelTimer                                                 , receiveAfter                                                 , receiveSelectedAfter+                                                , receiveSelectedWithMonitorAfter                                                 )  import           Control.Eff.Concurrent.Api     ( Api@@ -170,6 +172,7 @@ import           Control.Eff.Concurrent.Api.Client                                                 ( cast                                                 , call+                                                , callWithTimeout                                                 , castRegistered                                                 , callRegistered                                                 , ServesApi
src/Control/Eff/Concurrent/Api.hs view
@@ -30,6 +30,7 @@ import           Data.Typeable                  ( Typeable                                                 , typeRep                                                 )+import Control.DeepSeq (NFData)  -- | This data family defines an API, a communication interface description -- between at least two processes. The processes act as __servers__ or@@ -57,7 +58,6 @@ -- > data family Api (api :: Type) (reply :: Synchronicity) - -- | The (promoted) constructors of this type specify (at the type level) the -- reply behavior of a specific constructor of an @Api@ instance. data Synchronicity =@@ -70,8 +70,7 @@ -- | This is a tag-type that wraps around a 'ProcessId' and holds an 'Api' index -- type. newtype Server api = Server { _fromServer :: ProcessId }-  deriving (Eq,Ord,Typeable)-+  deriving (Eq,Ord,Typeable, NFData)  instance Typeable api => Show (Server api) where   showsPrec d s@(Server c) =
src/Control/Eff/Concurrent/Api/Client.hs view
@@ -5,6 +5,7 @@   ( -- * Calling APIs directly     cast   , call+  , callWithTimeout   -- * Server Process Registration   , castRegistered   , callRegistered@@ -20,6 +21,8 @@ import           Control.Eff.Concurrent.Api import           Control.Eff.Concurrent.Api.Request import           Control.Eff.Concurrent.Process+import           Control.Eff.Concurrent.Process.Timer+import           Control.Eff.Log import           Data.Typeable                  ( Typeable ) import           Control.DeepSeq import           GHC.Stack@@ -28,6 +31,8 @@ -- possible. The type signature enforces that the corresponding 'Api' clause is -- 'Asynchronous'. The operation never fails, if it is important to know if the -- message was delivered, use 'call' instead.+--+-- The message will be reduced to normal form ('rnf') in the caller process. cast   :: forall r q o    . ( HasCallStack@@ -35,33 +40,37 @@      , Member Interrupts r      , Typeable o      , Typeable (Api o 'Asynchronous)+     , NFData (Api o 'Asynchronous)      )   => Server o   -> Api o 'Asynchronous   -> Eff r ()-cast (Server pid) castMsg = sendMessage pid (Cast $! castMsg)+cast (Server pid) castMsg = sendMessage pid (Cast castMsg)  -- | Send an 'Api' request and wait for the server to return a result value. -- -- The type signature enforces that the corresponding 'Api' clause is -- 'Synchronous'.+--+-- __Always prefer 'callWithTimeout' over 'call'__ call   :: forall result api r q    . ( SetMember Process (Process q) r      , Member Interrupts r      , Typeable api      , Typeable (Api api ( 'Synchronous result))+     , NFData (Api api ( 'Synchronous result))      , Typeable result-     , HasCallStack      , NFData result      , Show result+     , HasCallStack      )   => Server api   -> Api api ( 'Synchronous result)   -> Eff r result call (Server pidInternal) req = do-  fromPid <- self   callRef <- makeReference+  fromPid <- self   let requestMessage = Call callRef fromPid $! req   sendMessage pidInternal requestMessage   let selectResult :: MessageSelector result@@ -74,6 +83,64 @@   resultOrError <- receiveWithMonitor pidInternal selectResult   either (interrupt . becauseProcessIsDown) return resultOrError ++-- | Send an 'Api' request and wait for the server to return a result value.+--+-- The type signature enforces that the corresponding 'Api' clause is+-- 'Synchronous'.+--+-- If the server that was called dies, this function interrupts the+-- process with 'ProcessDown'.+-- If the server takes longer to reply than the given timeout, this+-- function interrupts the process with 'ProcessTimeout'.+--+-- __Always prefer this function over 'call'__+--+-- @since 0.22.0+callWithTimeout+  :: forall result api r q+   . ( SetMember Process (Process q) r+     , Member Interrupts r+     , Typeable api+     , Typeable (Api api ( 'Synchronous result))+     , NFData (Api api ( 'Synchronous result))+     , Typeable result+     , NFData result+     , Show result+     , Member Logs r+     , Lifted IO q+     , Lifted IO r+     , HasCallStack+     )+  => Server api+  -> Api api ( 'Synchronous result)+  -> Timeout+  -> Eff r result+callWithTimeout serverP@(Server pidInternal) req timeOut = do+  fromPid <- self+  callRef <- makeReference+  let requestMessage = Call callRef fromPid $! req+  sendMessage pidInternal requestMessage+  let selectResult =+        let extractResult+              :: Reply (Api api ( 'Synchronous result)) -> Maybe result+            extractResult (Reply _pxResult callRefMsg result) =+              if callRefMsg == callRef then Just result else Nothing+        in selectMessageWith extractResult+  resultOrError <- receiveSelectedWithMonitorAfter pidInternal selectResult timeOut+  let onTimeout timerRef = do+        let msg = "call timed out after "+                  ++ show timeOut ++ " to server: "+                  ++ show serverP ++ " from "+                  ++ show fromPid ++ " "+                  ++ show timerRef+        logWarning' msg+        interrupt (ProcessTimeout msg)+      onProcDown p = do+        logWarning' ("call to dead server: "++ show serverP ++ " from " ++ show fromPid)+        interrupt (becauseProcessIsDown p)+  either (either onProcDown onTimeout) return resultOrError+ -- | Instead of passing around a 'Server' value and passing to functions like -- 'cast' or 'call', a 'Server' can provided by a 'Reader' effect, if there is -- only a __single server__ for a given 'Api' instance. This type alias is@@ -106,6 +173,7 @@      , HasCallStack      , NFData reply      , Show reply+     , NFData (Api o ( 'Synchronous reply))      , Member Interrupts r      )   => Api o ( 'Synchronous reply)@@ -117,7 +185,7 @@ -- | Like 'cast' but take the 'Server' from the reader provided by -- 'registerServer'. castRegistered-  :: (Typeable o, ServesApi o r q, HasCallStack, Member Interrupts r)+  :: (Typeable o, ServesApi o r q, HasCallStack, Member Interrupts r, NFData (Api o 'Asynchronous))   => Api o 'Asynchronous   -> Eff r () castRegistered method = do
+ src/Control/Eff/Concurrent/Api/GenServer.hs view
@@ -0,0 +1,49 @@+-- | A better, more safe implementation of the Erlang/OTP gen_server behaviour.+-- **PLANNED TODO**+-- @since 0.23.0+module Control.Eff.Concurrent.Api.GenServer++   where++import Control.DeepSeq+import Control.Eff+import Control.Eff.Concurrent.Api+import Control.Eff.Concurrent.Process+import Control.Eff.Log+import Control.Eff.State.Lazy+import Data.Dynamic+import Data.Kind+import Data.Text as T++-- | A type class for 'Api' values that have an implementation+-- which handles the 'Api'.+class (Typeable (GenServerState a), NFData (GenServerState a)) =>+      GenServer a eff+  where+  type GenServerState a :: Type+  genServerInit :: ('[Interrupts, Logs] <:: eff, SetMember Process (Process q) eff) => a -> Eff eff (GenServerState a)+  genServerHandle ::+       ('[Interrupts, Logs] <:: eff, SetMember Process (Process q) eff)+    => Api a v+    -> Eff (State (GenServerState a) ': eff) (ApiReply v)+  genServerInterrupt ::+       ('[Interrupts, Logs] <:: eff, SetMember Process (Process q) eff)+    => InterruptReason+    -> Eff (State (GenServerState a) ': eff) ()+  genServerInfoCommand :: Api a ('Synchronous Text)++type family ApiReply (s :: Synchronicity) where+  ApiReply ('Synchronous t) = Maybe t+  ApiReply 'Asynchronous = ()++data SomeMessage a =+  MkSomeMessage++data instance  Api (SomeMessage a) s where+        SomeMessage :: a -> Api (SomeMessage a) 'Asynchronous++runGenServer ::+     forall q e h a. (GenServer a e, SetMember Process (Process q) e, Member Interrupts e, LogsTo h e)+  => a+  -> Eff e (Server a)+runGenServer initArg = error "TODO"
src/Control/Eff/Concurrent/Api/Observer.hs view
@@ -26,14 +26,18 @@ import           Control.Eff.Concurrent.Api.Client import           Control.Eff.Concurrent.Api.Server import           Control.Eff.State.Strict+import           Control.Eff.Log import           Control.Lens+import           Data.Data                     (typeOf) import           Data.Dynamic import           Data.Foldable import           Data.Proxy import           Data.Set                       ( Set ) import qualified Data.Set                      as Set+import           Data.Text                      ( pack ) import           Data.Typeable                  ( typeRep ) import           GHC.Stack+import Control.DeepSeq (NFData(rnf))  -- * Observers @@ -45,9 +49,12 @@ -- @since 0.16.0 data Observer o where   Observer-    :: (Show (Server p), Typeable p, Typeable o)+    :: (Show (Server p), Typeable p, Typeable o, NFData o, NFData (Api p 'Asynchronous))     => (o -> Maybe (Api p 'Asynchronous)) -> Server p -> Observer o +instance (NFData o) => NFData (Observer o) where+  rnf (Observer k s) = rnf k `seq` rnf s+ instance Show (Observer o) where   showsPrec d (Observer _ p) = showParen     (d >= 10)@@ -72,6 +79,7 @@      , HasCallStack      , Member Interrupts r      , Typeable o+     , NFData o      )   => Observer o   -> Server (ObserverRegistry o)@@ -87,6 +95,7 @@      , HasCallStack      , Member Interrupts r      , Typeable o+     , NFData o      )   => Observer o   -> Server (ObserverRegistry o)@@ -106,14 +115,18 @@   --   -- @since 0.16.1   Observed :: o -> Api (Observer o) 'Asynchronous+  deriving Typeable +instance NFData o => NFData (Api (Observer o) 'Asynchronous) where+  rnf (Observed o) = rnf o+ -- | Based on the 'Api' instance for 'Observer' this simplified writing -- a callback handler for observations. In order to register to -- and 'ObserverRegistry' use 'toObserver'. -- -- @since 0.16.0 handleObservations-  :: (HasCallStack, Typeable o, SetMember Process (Process q) r)+  :: (HasCallStack, Typeable o, SetMember Process (Process q) r, NFData (Observer o))   => (o -> Eff r CallbackResult)   -> MessageCallback (Observer o) r handleObservations k = handleCasts@@ -124,7 +137,7 @@ -- | Use a 'Server' as an 'Observer' for 'handleObservations'. -- -- @since 0.16.0-toObserver :: Typeable o => Server (Observer o) -> Observer o+toObserver :: (NFData o, Typeable o, NFData (Api (Observer o) 'Asynchronous)) => Server (Observer o) -> Observer o toObserver = toObserverFor Observed  -- | Create an 'Observer' that conditionally accepts all observations of the@@ -133,7 +146,7 @@ -- -- @since 0.16.0 toObserverFor-  :: (Typeable a, Typeable o)+  :: (Typeable a, NFData (Api a 'Asynchronous), Typeable o, NFData o)   => (o -> Api a 'Asynchronous)   -> Server a   -> Observer o@@ -156,12 +169,16 @@   --   received.   --   -- @since 0.16.1-  RegisterObserver :: Observer o -> Api (ObserverRegistry o) 'Asynchronous+  RegisterObserver :: NFData o => Observer o -> Api (ObserverRegistry o) 'Asynchronous   -- | This message denotes that the given 'Observer' should not receive observations anymore.   --   -- @since 0.16.1-  ForgetObserver :: Observer o -> Api (ObserverRegistry o) 'Asynchronous+  ForgetObserver :: NFData o => Observer o -> Api (ObserverRegistry o) 'Asynchronous+  deriving Typeable +instance NFData (Api (ObserverRegistry o) r) where+  rnf (RegisterObserver o) = rnf o+  rnf (ForgetObserver o) = rnf o  -- ** Api for integrating 'ObserverRegistry' into processes. @@ -175,20 +192,27 @@      , Typeable o      , SetMember Process (Process q) r      , Member (ObserverState o) r+     , Member Logs r      )   => MessageCallback (ObserverRegistry o) r handleObserverRegistration = handleCasts   (\case-    RegisterObserver ob ->-      get @(Observers o)-        >>= put-        .   over observers (Set.insert ob)-        >>  pure AwaitNext-    ForgetObserver ob ->-      get @(Observers o)-        >>= put-        .   over observers (Set.delete ob)-        >>  pure AwaitNext+    RegisterObserver ob -> do+      os <- get @(Observers o)+      logDebug ("registering "+               <> pack (show (typeOf ob))+               <> " current number of observers: "+               <> pack (show (Set.size (view observers os))))+      put (over observers (Set.insert ob)os)+      pure AwaitNext+    ForgetObserver ob -> do+      os <- get @(Observers o)+      logDebug ("forgetting "+               <> pack (show (typeOf ob))+               <> " current number of observers: "+               <> pack (show (Set.size (view observers os))))+      put (over observers (Set.delete ob) os)+      pure AwaitNext   )  @@ -201,7 +225,7 @@ manageObservers = evalState (Observers Set.empty)  -- | Internal state for 'manageObservers'-data Observers o =+newtype Observers o =   Observers { _observers :: Set (Observer o) }  -- | Alias for the effect that contains the observers managed by 'manageObservers'@@ -219,6 +243,7 @@    . ( SetMember Process (Process q) r      , Member (ObserverState o) r      , Member Interrupts r+   --  , NFData (Api o 'Asynchronous)      )   => o   -> Eff r ()
src/Control/Eff/Concurrent/Api/Observer/Queue.hs view
@@ -11,12 +11,14 @@ where  import           Control.Concurrent.STM+import           Control.DeepSeq (NFData) import           Control.Eff-import           Control.Eff.ExceptionExtra     ( )-import           Control.Eff.Concurrent.Process-import           Control.Eff.Log+import           Control.Eff.Concurrent.Api import           Control.Eff.Concurrent.Api.Observer import           Control.Eff.Concurrent.Api.Server+import           Control.Eff.Concurrent.Process+import           Control.Eff.ExceptionExtra     ( )+import           Control.Eff.Log import           Control.Eff.Reader.Strict import           Control.Exception.Safe        as Safe import           Control.Monad.IO.Class@@ -134,7 +136,13 @@ -- @since 0.18.0 spawnLinkObservationQueueWriter   :: forall o q-   . (Typeable o, Show o, Member Logs q, Lifted IO q, HasCallStack)+   . ( Typeable o+     , Show o+     , NFData o+     , NFData (Api (Observer o) 'Asynchronous)+     , Member Logs q+     , Lifted IO q+     , HasCallStack)   => ObservationQueue o   -> Eff (InterruptableProcess q) (Observer o) spawnLinkObservationQueueWriter (ObservationQueue q) = do
src/Control/Eff/Concurrent/Api/Request.hs view
@@ -24,20 +24,29 @@ -- -- @since 0.15.0 data Request api where-  Call :: forall api reply . (Typeable api, Typeable reply, Typeable (Api api ('Synchronous reply)))+  Call :: forall api reply . (Typeable api, Typeable reply, NFData reply, Typeable (Api api ('Synchronous reply)), NFData (Api api ('Synchronous reply)))          => Int -> ProcessId -> Api api ('Synchronous reply) -> Request api -  Cast :: forall api . (Typeable api, Typeable (Api api 'Asynchronous))+  Cast :: forall api . (Typeable api, Typeable (Api api 'Asynchronous), NFData (Api api 'Asynchronous ))          => Api api 'Asynchronous -> Request api   deriving Typeable +instance NFData (Request api) where+  rnf (Call i p req) = rnf i `seq` rnf p `seq` rnf req+  rnf (Cast req)     = rnf req+ -- | The wrapper around replies to 'Call's. -- -- @since 0.15.0 data Reply request where-  Reply :: (Typeable api, Typeable reply) => Proxy (Api api ('Synchronous reply)) -> Int -> reply -> Reply (Api api ('Synchronous reply))+  Reply :: (Typeable api, Typeable reply, NFData reply)+        => Proxy (Api api ('Synchronous reply)) -> Int -> reply -> Reply (Api api ('Synchronous reply))   deriving Typeable +instance NFData (Reply request) where+  rnf (Reply _ i r) = rnf i `seq` rnf r++ -- | Get the @reply@ of an @Api foo ('Synchronous reply)@. -- -- @since 0.15.0@@ -61,12 +70,18 @@ -- @since 0.15.0 data RequestOrigin request =   RequestOrigin { _requestOriginPid :: !ProcessId, _requestOriginCallRef :: !Int}-  deriving (Eq, Ord, Typeable, Show, Generic)+  deriving (Eq, Ord, Typeable, Generic) +instance Show (RequestOrigin r) where+  showsPrec d (RequestOrigin o r) =+    showParen (d >= 10) (showString "caller: " . shows o . showChar ' ' . shows r)+ instance NFData (RequestOrigin request) where  -- | Send a 'Reply' to a 'Call'. --+-- The reply will be deeply evaluated to 'rnf'.+-- -- @since 0.15.0 sendReply   :: forall request reply api eff q@@ -77,10 +92,11 @@      , ReplyType request ~ reply      , request ~ Api api ( 'Synchronous reply)      , Typeable reply+     , NFData reply      )   => RequestOrigin request   -> reply   -> Eff eff () sendReply origin reply = sendMessage   (_requestOriginPid origin)-  (Reply (Proxy @request) (_requestOriginCallRef origin) $! reply)+  (Reply (Proxy @request) (_requestOriginCallRef origin) $! force reply)
src/Control/Eff/Concurrent/Api/Server.hs view
@@ -41,7 +41,7 @@ import           Control.Eff import           Control.Eff.Extend import           Control.Eff.Log-import           Control.Eff.State.Lazy+import           Control.Eff.State.Strict import           Control.Eff.Concurrent.Api import           Control.Eff.Concurrent.Api.Request import           Control.Eff.Concurrent.Process@@ -55,6 +55,7 @@ import           Data.Text as T import           GHC.Stack + -- | /Serve/ an 'Api' in a newly spawned process. -- -- @since 0.13.2@@ -85,7 +86,7 @@ -- @since 0.13.2 spawnApiServerStateful   :: forall api eff state-   . (HasCallStack, ToServerPids api)+   . (HasCallStack, ToServerPids api, NFData state)   => Eff (InterruptableProcess eff) state   -> MessageCallback api (State state ': InterruptableProcess eff)   -> InterruptCallback (State state ': ConsProcess eff)@@ -96,12 +97,15 @@     evalState state $ receiveSelectedLoop sel $ \msg -> case msg of       Left  m -> invokeIntCb m       Right m -> do-        s <- get-        r <- raise (provideInterrupts (evalState s (cb m)))+        r <- do s <- force <$> get+                raise (provideInterrupts (runState s (cb m)))         case r of-          Left  i              -> invokeIntCb i-          Right (StopServer i) -> invokeIntCb i-          Right AwaitNext      -> return Nothing+          Left  i                  -> invokeIntCb i+          Right (x , s')           -> do+            put (force s')+            case x of+              (StopServer i) -> invokeIntCb i+              AwaitNext      -> return Nothing  where   invokeIntCb j = do     l <- intCb j@@ -201,7 +205,7 @@ -- | An existential wrapper around  a 'MessageSelector' and a function that -- handles the selected message. The @api@ type parameter is a phantom type. ----- The return value if the handler function is a 'CallbackResult'.+-- The return value of the handler function is a 'CallbackResult'. -- -- @since 0.13.2 data MessageCallback api eff where@@ -213,7 +217,7 @@  instance Monoid (MessageCallback api eff) where   mappend = (<>)-  mempty  = MessageCallback selectAnyMessageLazy (const (pure AwaitNext))+  mempty  = MessageCallback selectAnyMessage (const (pure AwaitNext))  instance Default (MessageCallback api eff) where   def = mempty@@ -245,20 +249,21 @@ handleAnyMessages   :: forall eff    . HasCallStack-  => (Dynamic -> Eff eff CallbackResult)+  => (StrictDynamic -> Eff eff CallbackResult)   -> MessageCallback '[] eff-handleAnyMessages = MessageCallback selectAnyMessageLazy+handleAnyMessages = MessageCallback selectAnyMessage  -- | A smart constructor for 'MessageCallback's -- -- @since 0.13.2 handleCasts   :: forall api eff-   . (HasCallStack, Typeable api, Typeable (Api api 'Asynchronous))+   . ( HasCallStack, Typeable api, Typeable (Api api 'Asynchronous)+     , NFData (Request api))   => (Api api 'Asynchronous -> Eff eff CallbackResult)   -> MessageCallback api eff handleCasts h = MessageCallback-  (selectMessageWithLazy+  (selectMessageWith     (\case       cr@(Cast _ :: Request api) -> Just cr       _callReq                   -> Nothing@@ -291,14 +296,14 @@      , Member Interrupts eff      )   => (  forall secret reply-      . (Typeable reply, Typeable (Api api ( 'Synchronous reply)))+      . (NFData reply, Typeable reply, Typeable (Api api ( 'Synchronous reply)))      => Api api ( 'Synchronous reply)      -> (Eff eff (Maybe reply, CallbackResult) -> secret)      -> secret      )   -> MessageCallback api eff handleCalls h = MessageCallback-  (selectMessageWithLazy+  (selectMessageWith     (\case       (Cast _ :: Request api) -> Nothing       callReq                 -> Just callReq@@ -322,12 +327,13 @@    . ( HasCallStack      , Typeable api      , Typeable (Api api 'Asynchronous)+     , NFData (Request api)      , SetMember Process (Process effScheduler) eff      , Member Interrupts eff      )   => (Api api 'Asynchronous -> Eff eff CallbackResult)   -> (  forall secret reply-      . (Typeable reply, Typeable (Api api ( 'Synchronous reply)))+      . (Typeable reply, Typeable (Api api ( 'Synchronous reply)), NFData reply)      => Api api ( 'Synchronous reply)      -> (Eff eff (Maybe reply, CallbackResult) -> secret)      -> secret@@ -347,14 +353,14 @@      , Member Interrupts eff      )   => (  forall reply-      . (Typeable reply, Typeable (Api api ( 'Synchronous reply)))+      . (Typeable reply, NFData reply, Typeable (Api api ( 'Synchronous reply)))      => RequestOrigin (Api api ( 'Synchronous reply))      -> Api api ( 'Synchronous reply)      -> Eff eff CallbackResult      )   -> MessageCallback api eff handleCallsDeferred h = MessageCallback-  (selectMessageWithLazy+  (selectMessageWith     (\case       (Cast _ :: Request api) -> Nothing       callReq                 -> Just callReq@@ -410,13 +416,13 @@ -- @since 0.13.2 dropUnhandledMessages :: forall eff . HasCallStack => MessageCallback '[] eff dropUnhandledMessages =-  MessageCallback selectAnyMessageLazy (const (return AwaitNext))+  MessageCallback selectAnyMessage (const (return AwaitNext))  -- | A 'fallbackHandler' that terminates if there are unhandled messages. -- -- @since 0.13.2 exitOnUnhandled :: forall eff . HasCallStack => MessageCallback '[] eff-exitOnUnhandled = MessageCallback selectAnyMessageLazy $ \msg ->+exitOnUnhandled = MessageCallback selectAnyMessage $ \msg ->   return (StopServer (ProcessError ("unhandled message " <> show msg)))  -- | A 'fallbackHandler' that drops the left-over messages.@@ -426,7 +432,7 @@   :: forall eff    . (Member Logs eff, HasCallStack)   => MessageCallback '[] eff-logUnhandledMessages = MessageCallback selectAnyMessageLazy $ \msg -> do+logUnhandledMessages = MessageCallback selectAnyMessage $ \msg -> do   logWarning ("ignoring unhandled message " <> T.pack (show msg))   return AwaitNext 
src/Control/Eff/Concurrent/Process.hs view
@@ -15,14 +15,16 @@   ( -- * Process Effect     -- ** Effect Type Handling     Process(..)+  , -- ** Message Data+    StrictDynamic()+  , toStrictDynamic+  , fromStrictDynamic+  , unwrapStrictDynamic     -- ** ProcessId Type   , ProcessId(..)   , fromProcessId   , ConsProcess   , ResumeProcess(..)-  -- ** Scheduler Effect Identification-  , SchedulerProxy(..)-  , thisSchedulerProxy   -- ** Process State   , ProcessState(..)   -- ** Yielding@@ -45,16 +47,10 @@   -- ** Selecting Messages to Receive   , MessageSelector(runMessageSelector)   , selectMessage-  , selectMessageLazy-  , selectMessageProxy-  , selectMessageProxyLazy   , filterMessage-  , filterMessageLazy   , selectMessageWith-  , selectMessageWithLazy   , selectDynamicMessage-  , selectDynamicMessageLazy-  , selectAnyMessageLazy+  , selectAnyMessage   -- ** Process Life Cycle Management   , self   , isProcessAlive@@ -135,6 +131,7 @@ import qualified Data.Text                     as T import qualified Control.Exception             as Exc + -- | The process effect is the basis for message passing concurrency. This -- effect describes an interface for concurrent, communicating isolated -- processes identified uniquely by a process-id.@@ -160,7 +157,7 @@ -- * when the first process exists, all process should be killed immediately data Process (r :: [Type -> Type]) b where   -- | Remove all messages from the process' message queue-  FlushMessages ::Process r (ResumeProcess [Dynamic])+  FlushMessages ::Process r (ResumeProcess [StrictDynamic])   -- | In cooperative schedulers, this will give processing time to the   -- scheduler. Every other operation implicitly serves the same purpose.   --@@ -190,7 +187,7 @@   -- message should __always succeed__ and return __immediately__, even if the   -- destination process does not exist, or does not accept messages of the   -- given type.-  SendMessage ::ProcessId -> Dynamic -> Process r (ResumeProcess ())+  SendMessage :: ProcessId -> StrictDynamic -> Process r (ResumeProcess ())   -- | Receive a message that matches a criteria.   -- This should block until an a message was received. The message is returned   -- as a 'ResumeProcess' value. The function should also return if an exception@@ -261,6 +258,40 @@     Link      l                -> showString "link " . shows l     Unlink    l                -> showString "unlink " . shows l +-- | Data flows between 'Process'es via these messages.+--+-- This is just a newtype wrapper around 'Dynamic'.+-- The reason this type exists is to force construction through the code in this+-- module, which always evaluates a message to /normal form/ __before__+-- sending it to another process.+--+-- @since 0.22.0+newtype StrictDynamic where+  MkDynamicMessage :: Dynamic -> StrictDynamic+  deriving Typeable++instance Show StrictDynamic where+  show (MkDynamicMessage d) = show d++-- | Deeply evaluate the given value and wrap it into a 'StrictDynamic'.+--+-- @since 0.22.0+toStrictDynamic :: (Typeable a, NFData a) => a -> StrictDynamic+toStrictDynamic x = force x `seq` toDyn (force x) `seq` MkDynamicMessage (toDyn (force x))++-- | Convert a 'StrictDynamic' back to a value.+--+-- @since 0.22.0+fromStrictDynamic :: Typeable a => StrictDynamic -> Maybe a+fromStrictDynamic (MkDynamicMessage d) = fromDynamic d+++-- | Convert a 'StrictDynamic' back to an unwrapped 'Dynamic'.+--+-- @since 0.22.0+unwrapStrictDynamic :: StrictDynamic -> Dynamic+unwrapStrictDynamic (MkDynamicMessage d) = d+ -- | Every 'Process' action returns it's actual result wrapped in this type. It -- will allow to signal errors as well as pass on normal results such as -- incoming messages.@@ -292,7 +323,7 @@ -- >   Left <$> selectTimeout<|> Right <$> selectString -- newtype MessageSelector a =-  MessageSelector {runMessageSelector :: Dynamic -> Maybe a }+  MessageSelector {runMessageSelector :: StrictDynamic -> Maybe a }   deriving (Semigroup, Monoid, Functor)  instance Applicative MessageSelector where@@ -305,111 +336,47 @@   (MessageSelector l) <|> (MessageSelector r) =     MessageSelector (\dyn -> l dyn <|> r dyn) --- | Create a message selector for a value that can be obtained by 'fromDynamic'.--- It will also 'force' the result.------ @since 0.9.1-selectMessage :: (NFData t, Typeable t) => MessageSelector t-selectMessage = selectDynamicMessage fromDynamic---- | Create a message selector for a value that can be obtained by 'fromDynamic'.--- It will also 'force' the result.+-- | Create a message selector for a value that can be obtained by 'fromStrictDynamic'. -- -- @since 0.9.1-selectMessageLazy :: Typeable t => MessageSelector t-selectMessageLazy = selectDynamicMessageLazy fromDynamic+selectMessage :: Typeable t => MessageSelector t+selectMessage = selectDynamicMessage fromStrictDynamic --- | Create a message selector from a predicate. It will 'force' the result.+-- | Create a message selector from a predicate. -- -- @since 0.9.1-filterMessage :: (Typeable a, NFData a) => (a -> Bool) -> MessageSelector a+filterMessage :: Typeable a => (a -> Bool) -> MessageSelector a filterMessage predicate = selectDynamicMessage-  (\d -> case fromDynamic d of-    Just a | predicate a -> Just a-    _                    -> Nothing-  )---- | Create a message selector from a predicate. It will 'force' the result.------ @since 0.9.1-filterMessageLazy :: Typeable a => (a -> Bool) -> MessageSelector a-filterMessageLazy predicate = selectDynamicMessageLazy-  (\d -> case fromDynamic d of+  (\d -> case fromStrictDynamic d of     Just a | predicate a -> Just a     _                    -> Nothing   )  -- | Select a message of type @a@ and apply the given function to it. -- If the function returns 'Just' The 'ReceiveSelectedMessage' function will--- return the result (sans @Maybe@). It will 'force' the result.+-- return the result (sans @Maybe@). -- -- @since 0.9.1 selectMessageWith-  :: (Typeable a, NFData b) => (a -> Maybe b) -> MessageSelector b-selectMessageWith f = selectDynamicMessage (fromDynamic >=> f)---- | Select a message of type @a@ and apply the given function to it.--- If the function returns 'Just' The 'ReceiveSelectedMessage' function will--- return the result (sans @Maybe@). It will 'force' the result.------ @since 0.9.1-selectMessageWithLazy :: Typeable a => (a -> Maybe b) -> MessageSelector b-selectMessageWithLazy f = selectDynamicMessageLazy (fromDynamic >=> f)---- | Create a message selector. It will 'force' the result.------ @since 0.9.1-selectDynamicMessage :: NFData a => (Dynamic -> Maybe a) -> MessageSelector a-selectDynamicMessage = MessageSelector . (force .)+  :: Typeable a => (a -> Maybe b) -> MessageSelector b+selectMessageWith f = selectDynamicMessage (fromStrictDynamic >=> f)  -- | Create a message selector. -- -- @since 0.9.1-selectDynamicMessageLazy :: (Dynamic -> Maybe a) -> MessageSelector a-selectDynamicMessageLazy = MessageSelector+selectDynamicMessage :: (StrictDynamic -> Maybe a) -> MessageSelector a+selectDynamicMessage = MessageSelector  -- | Create a message selector that will match every message. This is /lazy/ -- because the result is not 'force'ed. -- -- @since 0.9.1-selectAnyMessageLazy :: MessageSelector Dynamic-selectAnyMessageLazy = MessageSelector Just---- | Create a message selector for a value that can be obtained by 'fromDynamic'--- with a proxy argument. It will also 'force' the result.------ @since 0.9.1-selectMessageProxy-  :: forall proxy t . (NFData t, Typeable t) => proxy t -> MessageSelector t-selectMessageProxy _ = selectDynamicMessage fromDynamic---- | Create a message selector for a value that can be obtained by 'fromDynamic'--- with a proxy argument. It will also 'force' the result.------ @since 0.9.1-selectMessageProxyLazy-  :: forall proxy t . (Typeable t) => proxy t -> MessageSelector t-selectMessageProxyLazy _ = selectDynamicMessageLazy fromDynamic---- | Every function for 'Process' things needs such a proxy value--- for the low-level effect list, i.e. the effects identified by--- @__r__@ in @'Process' r : r@, this might be dependent on the--- scheduler implementation.-data SchedulerProxy :: [Type -> Type] -> Type where-  -- | Tell the type checker what effects we have below 'Process'-  SchedulerProxy ::SchedulerProxy q-  -- | Like 'SchedulerProxy' but shorter-  SP ::SchedulerProxy q-  -- | Like 'SP' but different-  Scheduler ::SchedulerProxy q+selectAnyMessage :: MessageSelector StrictDynamic+selectAnyMessage = MessageSelector Just  -- | /Cons/ 'Process' onto a list of effects. type ConsProcess r = Process r ': r --- | Return a 'SchedulerProxy' for a 'Process' effect.-thisSchedulerProxy :: Eff (Process r ': r) (SchedulerProxy r)-thisSchedulerProxy = return SchedulerProxy- -- | The state that a 'Process' is currently in. data ProcessState =     ProcessBooting              -- ^ The process has just been started but not@@ -453,6 +420,7 @@ toExitRecovery = \case   ProcessFinished           -> Recoverable   (ProcessNotRunning    _)  -> Recoverable+  (ProcessTimeout       _)  -> Recoverable   (LinkedProcessCrashed _)  -> Recoverable   (ProcessError         _)  -> Recoverable   ExitNormally              -> NoRecovery@@ -493,42 +461,46 @@     --     -- @since 0.13.2     ProcessFinished-      ::ExitReason 'Recoverable+      :: ExitReason 'Recoverable     -- | A process that should be running was not running.     ProcessNotRunning-      ::ProcessId -> ExitReason 'Recoverable+      :: ProcessId -> ExitReason 'Recoverable+    -- | A 'Recoverable' timeout has occurred.+    ProcessTimeout+      :: String -> ExitReason 'Recoverable     -- | A linked process is down     LinkedProcessCrashed-      ::ProcessId -> ExitReason 'Recoverable-    -- | An exit reason that has an error message but isn't 'Recoverable'.+      :: ProcessId -> ExitReason 'Recoverable+    -- | An exit reason that has an error message and is 'Recoverable'.     ProcessError-      ::String -> ExitReason 'Recoverable+      :: String -> ExitReason 'Recoverable     -- | A process function returned or exited without any error.     ExitNormally-      ::ExitReason 'NoRecovery+      :: ExitReason 'NoRecovery     -- | An unhandled 'Recoverable' allows 'NoRecovery'.     NotRecovered-      ::(ExitReason 'Recoverable) -> ExitReason 'NoRecovery+      :: (ExitReason 'Recoverable) -> ExitReason 'NoRecovery     -- | An unexpected runtime exception was thrown, i.e. an exception     --    derived from 'Control.Exception.Safe.SomeException'     UnexpectedException-      ::String -> String -> ExitReason 'NoRecovery+      :: String -> String -> ExitReason 'NoRecovery     -- | A process was cancelled (e.g. killed, in 'Async.cancel')     Killed-      ::ExitReason 'NoRecovery+      :: ExitReason 'NoRecovery   deriving Typeable  instance Show (ExitReason x) where   showsPrec d =     showParen (d >= 10)       . (\case-          ProcessFinished     -> showString "process finished"-          ProcessNotRunning p -> showString "process not running: " . shows p+          ProcessFinished        -> showString "process finished"+          ProcessNotRunning p    -> showString "process not running: " . shows p+          ProcessTimeout reason -> showString "timeout: " . showString reason           LinkedProcessCrashed m ->             showString "linked process " . shows m . showString " crashed"-          ProcessError reason -> showString "error: " . showString reason-          ExitNormally        -> showString "exit normally"-          NotRecovered e      -> showString "not recovered from: " . shows e+          ProcessError reason   -> showString "error: " . showString reason+          ExitNormally          -> showString "exit normally"+          NotRecovered e        -> showString "not recovered from: " . shows e           UnexpectedException w m ->             showString "unhandled runtime exception: "               . showString m@@ -543,11 +515,12 @@ instance NFData (ExitReason x) where   rnf ProcessFinished               = rnf ()   rnf (ProcessNotRunning    !l)     = rnf l+  rnf (ProcessTimeout       !l)     = rnf l   rnf (LinkedProcessCrashed !l)     = rnf l   rnf (ProcessError         !l)     = rnf l   rnf ExitNormally                  = rnf ()   rnf (NotRecovered !l            ) = rnf l-  rnf (UnexpectedException !l1 !l2) = rnf l1 `seq` rnf l2 `seq` ()+  rnf (UnexpectedException !l1 !l2) = rnf l1 `seq` rnf l2   rnf Killed                        = rnf ()  instance Ord (ExitReason x) where@@ -557,6 +530,9 @@   compare (ProcessNotRunning l)    (ProcessNotRunning r)    = compare l r   compare (ProcessNotRunning _)    _                        = LT   compare _                        (ProcessNotRunning    _) = GT+  compare (ProcessTimeout l)       (ProcessTimeout r)       = compare l r+  compare (ProcessTimeout _) _                              = LT+  compare _                        (ProcessTimeout _)       = GT   compare (LinkedProcessCrashed l) (LinkedProcessCrashed r) = compare l r   compare (LinkedProcessCrashed _) _                        = LT   compare _                        (LinkedProcessCrashed _) = GT@@ -577,6 +553,7 @@   (==) ProcessFinished          ProcessFinished          = True   (==) (ProcessNotRunning l)    (ProcessNotRunning r)    = (==) l r   (==) ExitNormally             ExitNormally             = True+  (==) (ProcessTimeout l)       (ProcessTimeout r)       = l == r   (==) (LinkedProcessCrashed l) (LinkedProcessCrashed r) = l == r   (==) (ProcessError         l) (ProcessError         r) = (==) l r   (==) (NotRecovered         l) (NotRecovered         r) = (==) l r@@ -590,6 +567,7 @@ isBecauseDown mp = \case   ProcessFinished         -> False   ProcessNotRunning    _  -> False+  ProcessTimeout       _  -> False   LinkedProcessCrashed p  -> maybe True (== p) mp   ProcessError         _  -> False   ExitNormally            -> False@@ -710,10 +688,11 @@ fromSomeExitReason (SomeExitReason e) = case e of   recoverable@ProcessFinished          -> Right recoverable   recoverable@(ProcessNotRunning    _) -> Right recoverable+  recoverable@(ProcessTimeout       _) -> Right recoverable   recoverable@(LinkedProcessCrashed _) -> Right recoverable   recoverable@(ProcessError         _) -> Right recoverable   noRecovery@ExitNormally              -> Left noRecovery-  noRecovery@(NotRecovered _         ) -> Left noRecovery+  noRecovery@(NotRecovered          _) -> Left noRecovery   noRecovery@(UnexpectedException _ _) -> Left noRecovery   noRecovery@Killed                    -> Left noRecovery @@ -796,18 +775,21 @@ -- | Send a message to a process addressed by the 'ProcessId'. -- See 'SendMessage'. --+-- The message will be reduced to normal form ('rnf') by/in the caller process. sendMessage   :: forall r q o    . ( SetMember Process (Process q) r      , HasCallStack      , Member Interrupts r      , Typeable o+     , NFData o      )   => ProcessId   -> o   -> Eff r () sendMessage pid message =-  executeAndResumeOrThrow (SendMessage pid $! toDyn $! message)+  rnf pid `seq` toStrictDynamic message+          `seq` executeAndResumeOrThrow (SendMessage pid (toStrictDynamic message))  -- | Send a 'Dynamic' value to a process addressed by the 'ProcessId'. -- See 'SendMessage'.@@ -815,10 +797,10 @@   :: forall r q    . (SetMember Process (Process q) r, HasCallStack, Member Interrupts r)   => ProcessId-  -> Dynamic+  -> StrictDynamic   -> Eff r () sendAnyMessage pid message =-  rnf pid `seq` executeAndResumeOrThrow (SendMessage pid $! message)+  executeAndResumeOrThrow (SendMessage pid message)  -- | Exit a process addressed by the 'ProcessId'. The process will exit, -- it might do some cleanup, but is ultimately unrecoverable.@@ -910,9 +892,9 @@ receiveAnyMessage   :: forall r q    . (HasCallStack, SetMember Process (Process q) r, Member Interrupts r)-  => Eff r Dynamic+  => Eff r StrictDynamic receiveAnyMessage =-  executeAndResumeOrThrow (ReceiveSelectedMessage selectAnyMessageLazy)+  executeAndResumeOrThrow (ReceiveSelectedMessage selectAnyMessage)  -- | Block until a message was received, that is not 'Nothing' after applying -- a callback to it.@@ -935,12 +917,13 @@   :: forall a r q    . ( HasCallStack      , Typeable a+     , NFData a      , Show a      , SetMember Process (Process q) r      , Member Interrupts r      )   => Eff r a-receiveMessage = receiveSelectedMessage (MessageSelector fromDynamic)+receiveMessage = receiveSelectedMessage (MessageSelector fromStrictDynamic)  -- | Remove and return all messages currently enqueued in the process message -- queue.@@ -949,7 +932,7 @@ flushMessages   :: forall r q    . (HasCallStack, SetMember Process (Process q) r, Member Interrupts r)-  => Eff r [Dynamic]+  => Eff r [StrictDynamic] flushMessages = executeAndResumeOrThrow @q FlushMessages  -- | Enter a loop to receive messages and pass them to a callback, until the@@ -974,22 +957,22 @@   maybe (receiveSelectedLoop selector handlers) return mRes  -- | Like 'receiveSelectedLoop' but /not selective/.--- See also 'selectAnyMessageLazy', 'receiveSelectedLoop'.+-- See also 'selectAnyMessage', 'receiveSelectedLoop'. receiveAnyLoop   :: forall r q endOfLoopResult    . (SetMember Process (Process q) r, HasCallStack)-  => (Either InterruptReason Dynamic -> Eff r (Maybe endOfLoopResult))+  => (Either InterruptReason StrictDynamic -> Eff r (Maybe endOfLoopResult))   -> Eff r endOfLoopResult-receiveAnyLoop = receiveSelectedLoop selectAnyMessageLazy+receiveAnyLoop = receiveSelectedLoop selectAnyMessage  -- | Like 'receiveSelectedLoop' but refined to casting to a specific 'Typeable'--- using 'selectMessageLazy'.+-- using 'selectMessage'. receiveLoop   :: forall r q a endOfLoopResult-   . (SetMember Process (Process q) r, HasCallStack, Typeable a)+   . (SetMember Process (Process q) r, HasCallStack, NFData a, Typeable a)   => (Either InterruptReason a -> Eff r (Maybe endOfLoopResult))   -> Eff r endOfLoopResult-receiveLoop = receiveSelectedLoop selectMessageLazy+receiveLoop = receiveSelectedLoop selectMessage  -- | Returns the 'ProcessId' of the current process. self :: (HasCallStack, SetMember Process (Process q) r) => Eff r ProcessId@@ -1121,7 +1104,7 @@ -- @since 0.12.0 selectProcessDown :: MonitorReference -> MessageSelector ProcessDown selectProcessDown ref0 =-  filterMessageLazy (\(ProcessDown ref _reason) -> ref0 == ref)+  filterMessage (\(ProcessDown ref _reason) -> ref0 == ref)  -- | Connect the calling process to another process, such that -- if one of the processes crashes (i.e. 'isCrash' returns 'True'), the other
src/Control/Eff/Concurrent/Process/ForkIOScheduler.hs view
@@ -44,7 +44,6 @@                                                 , control                                                 ) import           Data.Default-import           Data.Dynamic import           Data.Foldable import           Data.Function                  ( fix ) import           Data.Kind                      ( )@@ -63,9 +62,9 @@ -- * Process Types  -- | A message queue of a process, contains the actual queue and maybe an--- exit reason. The message queue is backed by a 'Seq' sequence with 'Dynamic' values.+-- exit reason. The message queue is backed by a 'Seq' sequence with 'StrictDynamic' values. data MessageQ = MessageQ-  { _incomingMessages :: Seq Dynamic+  { _incomingMessages :: Seq StrictDynamic   , _shutdownRequests :: Maybe SomeExitReason   } @@ -109,6 +108,25 @@  makeLenses ''SchedulerState +logSchedulerState :: (HasCallStack, Member Logs e, Lifted IO e) => SchedulerState -> Eff e ()+logSchedulerState s = do+  (np, pt, pct, pm, nm) <- lift $ atomically $ do+    np  <- T.pack . show <$> readTVar (s ^. nextPid)+    pt  <- fmap (T.pack . show) <$> readTVar (s ^. processTable)+    pct <- fmap (T.pack . show) . Map.keys <$> readTVar (s ^. processCancellationTable)+    pm  <- fmap (T.pack . show) . Set.toList <$> readTVar (s ^. processMonitors)+    nm  <- T.pack . show <$> readTVar (s ^. nextMonitorIndex)+    return (np, pt, pct, pm, nm)+  logDebug "ForkIO Scheduler info"+  logDebug $ "nextPid: " <> np+  logDebug $ "process table:"+  traverse_ logDebug pt+  logDebug $ "process cancellation table:"+  traverse_ logDebug pct+  logDebug $ "process monitors:"+  traverse_ logDebug pm+  logDebug $ "nextMonitorIndex: " <> nm+ -- | Add monitor: If the process is dead, enqueue a 'ProcessDown' message into the -- owners message queue addMonitoring@@ -126,7 +144,7 @@         let processDownMessage =               ProcessDown monitorRef (SomeExitReason (ProcessNotRunning target))         in  enqueueMessageOtherProcess owner-                                       (toDyn processDownMessage)+                                       (toStrictDynamic processDownMessage)                                        schedulerState   return monitorRef @@ -145,7 +163,7 @@     (monitoredProcess mr == downPid)     (do       let processDownMessage = ProcessDown mr reason-      enqueueMessageOtherProcess owner (toDyn processDownMessage) schedulerState+      enqueueMessageOtherProcess owner (toStrictDynamic processDownMessage) schedulerState       removeMonitoring mr schedulerState     ) @@ -462,6 +480,8 @@     interpretGetProcessState !toPid = do       setMyProcessState ProcessBusy       schedulerState <- getSchedulerState+      when (toPid == 1) $+        logSchedulerState schedulerState       let procInfoVar = schedulerState ^. processTable       lift $ atomically $ do         procInfoTable <- readTVar procInfoVar@@ -495,7 +515,7 @@         >>= lift         .   atomically         .   enqueueShutdownRequest toPid msg-    interpretFlush :: Eff SchedulerIO (ResumeProcess [Dynamic])+    interpretFlush :: Eff SchedulerIO (ResumeProcess [StrictDynamic])     interpretFlush = do       setMyProcessState ProcessBusyReceiving       lift $ atomically $ do@@ -689,7 +709,7 @@ getSchedulerState = ask  enqueueMessageOtherProcess-  :: HasCallStack => ProcessId -> Dynamic -> SchedulerState -> STM ()+  :: HasCallStack => ProcessId -> StrictDynamic -> SchedulerState -> STM () enqueueMessageOtherProcess toPid msg schedulerState =   view (at toPid) <$> readTVar (schedulerState ^. processTable) >>= maybe     (return ())
src/Control/Eff/Concurrent/Process/Interactive.hs view
@@ -132,7 +132,7 @@ -- | Combination of 'submit' and 'cast'. submitCast   :: forall o r-   . (SetMember Lift (Lift IO) r, Typeable o, Member Interrupts r)+   . (SetMember Lift (Lift IO) r, Typeable o, NFData (Api o 'Asynchronous), Member Interrupts r)   => SchedulerSession r   -> Server o   -> Api o 'Asynchronous@@ -148,6 +148,7 @@      , NFData q      , Show q      , Member Interrupts r+     , NFData (Api o ('Synchronous q))      )   => SchedulerSession r   -> Server o
src/Control/Eff/Concurrent/Process/SingleThreadedScheduler.hs view
@@ -30,11 +30,11 @@ import qualified Data.Set                      as Set import           GHC.Stack import           Data.Kind                      ( )-import           Data.Dynamic import           Data.Foldable import           Data.Monoid import qualified Control.Monad.State.Strict    as State import Data.Function (fix)+import Data.Dynamic (dynTypeRep)  -- ----------------------------------------------------------------------------- --  STS@@ -43,7 +43,7 @@ data STS r m = STS   { _nextPid :: !ProcessId   , _nextRef :: !Int-  , _msgQs :: !(Map.Map ProcessId (Seq Dynamic))+  , _msgQs :: !(Map.Map ProcessId (Seq StrictDynamic))   , _monitors :: !(Set.Set (MonitorReference, ProcessId))   , _processLinks :: !(Set.Set (ProcessId, ProcessId))   , _runEff :: forall a . Eff r a -> m a@@ -66,7 +66,7 @@         (foldMap           (\(pid, msgs) ->             Endo (showString "  " . shows pid . showString ": ")-              <> foldMap (Endo . shows . dynTypeRep) (toList msgs)+              <> foldMap (Endo . shows . dynTypeRep . unwrapStrictDynamic) (toList msgs)           )           (sts ^.. msgQs . itraversed . withIndex)         )@@ -84,7 +84,7 @@ incRef :: STS r m -> (Int, STS r m) incRef sts = (sts ^. nextRef, sts & nextRef %~ (+ 1)) -enqueueMsg :: ProcessId -> Dynamic -> STS r m -> STS r m+enqueueMsg :: ProcessId -> StrictDynamic -> STS r m -> STS r m enqueueMsg toPid msg = msgQs . ix toPid %~ (:|> msg)  newProcessQ :: Maybe ProcessId -> STS r m -> (ProcessId, STS r m)@@ -98,7 +98,7 @@             let (Nothing, stsQL) = addLink pid (sts ^. nextPid) stsQ in stsQL   ) -flushMsgs :: ProcessId -> STS m r -> ([Dynamic], STS m r)+flushMsgs :: ProcessId -> STS m r -> ([StrictDynamic], STS m r) flushMsgs pid = State.runState $ do   msgs <- msgQs . ix pid <<.= Empty   return (toList msgs)@@ -134,7 +134,7 @@       if Map.member target pt         then monitors %= Set.insert (mref, owner)         else let pdown = ProcessDown mref (SomeExitReason (ProcessNotRunning target))-              in State.modify' (enqueueMsg owner (toDyn pdown))+              in State.modify' (enqueueMsg owner (toStrictDynamic pdown))     return mref  removeMonitoring :: MonitorReference -> STS m r -> STS m r@@ -148,7 +148,7 @@   go (mr, owner) = when     (monitoredProcess mr == downPid)     (let pdown = ProcessDown mr reason-     in  State.modify' (enqueueMsg owner (toDyn pdown) . removeMonitoring mr)+     in  State.modify' (enqueueMsg owner (toStrictDynamic pdown) . removeMonitoring mr)     )  addLink :: ProcessId -> ProcessId -> STS m r -> (Maybe InterruptReason, STS m r)@@ -258,7 +258,7 @@ -- | Internal data structure that is part of the coroutine based scheduler -- implementation. data OnYield r a where-  OnFlushMessages :: (ResumeProcess [Dynamic] -> Eff r (OnYield r a))+  OnFlushMessages :: (ResumeProcess [StrictDynamic] -> Eff r (OnYield r a))                   -> OnYield r a   OnYield :: (ResumeProcess () -> Eff r (OnYield r a))          -> OnYield r a@@ -273,7 +273,7 @@   OnInterrupt :: ExitReason 'Recoverable                 -> (ResumeProcess b -> Eff r (OnYield r a))                 -> OnYield r a-  OnSend :: !ProcessId -> !Dynamic+  OnSend :: !ProcessId -> !StrictDynamic          -> (ResumeProcess () -> Eff r (OnYield r a))          -> OnYield r a   OnRecv :: MessageSelector b -> (ResumeProcess b -> Eff r (OnYield r a))
src/Control/Eff/Concurrent/Process/Timer.hs view
@@ -14,6 +14,7 @@   , selectTimerElapsed   , receiveAfter   , receiveSelectedAfter+  , receiveSelectedWithMonitorAfter   )    -- , receiveSelectedAfter, receiveAnyAfter, sendMessageAfter) where@@ -68,6 +69,32 @@   timerRef <- startTimer t   res      <- receiveSelectedMessage     (Left <$> selectTimerElapsed timerRef <|> Right <$> sel)+  cancelTimer timerRef+  return res++-- | Like 'receiveWithMonitor' combined with 'receiveSelectedAfter'.+--+-- @since 0.22.0+receiveSelectedWithMonitorAfter+  :: forall a r q+   . ( Lifted IO q+     , HasCallStack+     , SetMember Process (Process q) r+     , Member Interrupts r+     , Show a+     )+  => ProcessId+  -> MessageSelector a+  -> Timeout+  -> Eff r (Either (Either ProcessDown TimerElapsed) a)+receiveSelectedWithMonitorAfter pid sel t = do+  timerRef <- startTimer t+  res      <- withMonitor pid $ \pidMon -> do+                receiveSelectedMessage+                  (   Left . Left  <$> selectProcessDown pidMon+                  <|> Left . Right <$> selectTimerElapsed timerRef+                  <|> Right        <$> sel+                  )   cancelTimer timerRef   return res 
src/Control/Eff/Log/MessageRenderer.hs view
@@ -11,12 +11,14 @@   , renderRFC3164WithRFC5424Timestamps   , renderRFC3164WithTimestamp   , renderRFC5424-+  , renderRFC5424Header+  , renderRFC5424NoLocation    -- ** Partial Log Message Text Rendering   , renderSyslogSeverityAndFacility   , renderLogMessageSrcLoc   , renderMaybeLogMessageLens+  , renderLogMessageBodyNoLocation   , renderLogMessageBody   , renderLogMessageBodyFixWidth @@ -76,9 +78,15 @@ -- | Print the thread id, the message and the source file location, seperated by simple white space. renderLogMessageBody :: LogMessageRenderer T.Text renderLogMessageBody = T.unwords . filter (not . T.null) <$> sequence+  [ renderLogMessageBodyNoLocation+  , fromMaybe "" <$> renderLogMessageSrcLoc+  ]++-- | Print the thread id, the message and the source file location, seperated by simple white space.+renderLogMessageBodyNoLocation :: LogMessageRenderer T.Text+renderLogMessageBodyNoLocation = T.unwords . filter (not . T.null) <$> sequence   [ renderShowMaybeLogMessageLens "" lmThreadId   , view lmMessage-  , fromMaybe "" <$> renderLogMessageSrcLoc   ]  -- | Print the /body/ of a 'LogMessage' with fix size fields (60) for the message itself@@ -184,8 +192,28 @@       ]  -- | Render a 'LogMessage' according to the rules in the RFC-5424.+--+-- Equivalent to @'renderRFC5424Header' <> const " " <> 'renderLogMessageBody'@.+--+-- @since 0.21.0 renderRFC5424 :: LogMessageRenderer T.Text-renderRFC5424 l@(MkLogMessage _ _ ts hn an pid mi sd _ _ _) =+renderRFC5424  = renderRFC5424Header <> const " " <> renderLogMessageBody++-- | Render a 'LogMessage' according to the rules in the RFC-5424, like 'renderRFC5424' but+-- suppress the source location information.+--+-- Equivalent to @'renderRFC5424Header' <> const " " <> 'renderLogMessageBodyNoLocation'@.+--+-- @since 0.21.0+renderRFC5424NoLocation :: LogMessageRenderer T.Text+renderRFC5424NoLocation  = renderRFC5424Header <> const " " <> renderLogMessageBodyNoLocation++-- | Render the header and strucuted data of  a 'LogMessage' according to the rules in the RFC-5424, but do not+-- render the 'lmMessage'.+--+-- @since 0.22.0+renderRFC5424Header :: LogMessageRenderer T.Text+renderRFC5424Header l@(MkLogMessage _ _ ts hn an pid mi sd _ _ _) =   T.unwords     . filter (not . T.null)     $ [ renderSyslogSeverityAndFacility l <> "1" -- PRI VERSION
src/Control/Eff/LogWriter/Async.hs view
@@ -35,7 +35,7 @@ -- > -- withAsyncLogging-  :: (LogsTo IO e, Lifted IO e, MonadBaseControl IO (Eff e), Integral len)+  :: (Lifted IO e, MonadBaseControl IO (Eff e), Integral len)   => LogWriter IO   -> len -- ^ Size of the log message input queue. If the queue is full, message          -- are dropped silently.
src/Control/Eff/LogWriter/UnixSocket.hs view
@@ -8,9 +8,7 @@ import           Control.Eff                   as Eff import           Control.Eff.Log import           Control.Eff.LogWriter.IO-import           Control.Eff.LogWriter.Console import           Data.Text                     as T-import           Data.Text.IO                  as T import           Data.Text.Encoding            as T import qualified Control.Exception.Safe        as Safe import           Control.Monad                  ( void )@@ -70,19 +68,3 @@             )           )   )-  -- (Socket.socket :: IO (Socket.Socket Unix Datagram Socket.Default))-  -- (Safe.try @IO @Catch.SomeException . Socket.close)-  -- (\s -> case socketAddressUnixPath (T.encodeUtf8 (T.pack socketPath)) of-  --   Just addr -> do-  --     Socket.connect s addr-  --     ioE-  --       (mkLogWriterIO-  --         (\lmStr -> void-  --           $ Socket.send s (T.encodeUtf8 (render lmStr)) Socket.msgNoSignal-  --         )-  --       )--  --   Nothing -> do-  --     T.putStrLn $ "could not open unix domain socket: " <> T.pack socketPath-  --     ioE consoleLogWriter-  -- )
test/ForkIOScheduler.hs view
@@ -15,7 +15,6 @@                                                 ) import           Test.Tasty import           Test.Tasty.HUnit-import           Data.Dynamic import           Common  test_IOExceptionsIsolated :: TestTree@@ -54,10 +53,10 @@           assertBool "the other process was still running" wasStillRunningP1   | (busyWith , busyEffect) <-     [ ( "receiving"-      , void (send (ReceiveSelectedMessage @SchedulerIO selectAnyMessageLazy))+      , void (send (ReceiveSelectedMessage @SchedulerIO selectAnyMessage))       )     , ( "sending"-      , void (send (SendMessage @SchedulerIO 44444 (toDyn ("test message" :: String))))+      , void (send (SendMessage @SchedulerIO 44444 (toStrictDynamic ("test message" :: String))))       )     , ( "sending shutdown"       , void (send (SendShutdown @SchedulerIO 44444 ExitNormally))@@ -68,7 +67,7 @@         (send           (Spawn @SchedulerIO             (void-              (send (ReceiveSelectedMessage @SchedulerIO selectAnyMessageLazy))+              (send (ReceiveSelectedMessage @SchedulerIO selectAnyMessage))             )           )         )@@ -162,7 +161,7 @@             testMsg :: Float             testMsg   = 123             flushMessagesLoop = do-              res <- receiveSelectedAfter (selectDynamicMessageLazy Just) 0+              res <- receiveSelectedAfter (selectDynamicMessage Just) 0               case res of                 Left  _to -> return ()                 Right _   -> flushMessagesLoop@@ -177,7 +176,7 @@           res <- receiveAfter @Float 1000000           lift (res @?= Just testMsg)         flushMessagesLoop-        res <- receiveSelectedAfter (selectDynamicMessageLazy Just) 10000+        res <- receiveSelectedAfter (selectDynamicMessage Just) 10000         case res of           Left  _ -> return ()           Right x -> lift (False @? "unexpected message in queue " ++ show x)
test/ProcessBehaviourTestCases.hs view
@@ -2,7 +2,6 @@  import           Data.List                      ( sort ) import           Data.Foldable                  ( traverse_ )-import qualified Data.Dynamic                  as Dynamic import           Data.Typeable import           Control.Exception import           Control.Concurrent@@ -29,7 +28,9 @@ import           Common import           Control.Applicative import           Data.Void-import Control.Lens (view)+import           Control.Lens (view)+import           Control.DeepSeq+import GHC.Generics (Generic)  testInterruptReason :: InterruptReason testInterruptReason = ProcessError "test interrupt"@@ -87,6 +88,10 @@   ReturnToSender :: ProcessId -> String -> Api ReturnToSender ('Synchronous Bool)   StopReturnToSender :: Api ReturnToSender ('Synchronous ()) +instance NFData (Api ReturnToSender r) where+  rnf (ReturnToSender p s) = rnf p `seq` rnf s+  rnf StopReturnToSender = ()+ deriving instance Show (Api ReturnToSender x)  deriving instance Typeable (Api ReturnToSender x)@@ -214,12 +219,14 @@         )  -data Ping = Ping ProcessId-  deriving (Eq, Show)+newtype Ping = Ping ProcessId+  deriving (Eq, Show, Typeable, NFData)  data Pong = Pong-  deriving (Eq, Show)+  deriving (Eq, Show, Generic) +instance NFData Pong+ pingPongTests   :: forall r    . (Lifted IO r, LogsTo IO r)@@ -360,7 +367,7 @@               (spawn                 (do                   m <- receiveAnyMessage-                  void (sendMessage me m)+                  void (sendAnyMessage me m)                 )               )             )@@ -492,7 +499,7 @@               )             )           , ( "sending"-            , void (send (SendMessage @r 44444 (Dynamic.toDyn ("test message" :: String))))+            , void (send (SendMessage @r 44444 (toStrictDynamic ("test message" :: String))))             )           , ( "sending shutdown"             , void (send (SendShutdown @r 44444 ExitNormally))@@ -502,7 +509,7 @@             , void               (send                 (Spawn @r-                  (void (send (ReceiveSelectedMessage @r selectAnyMessageLazy)))+                  (void (send (ReceiveSelectedMessage @r selectAnyMessage)))                 )               )             )@@ -524,7 +531,7 @@               )             )           , ( "sending"-            , void (send (SendMessage @r 44444 (Dynamic.toDyn ("test message"::String))))+            , void (send (SendMessage @r 44444 (toStrictDynamic ("test message"::String))))             )           , ( "sending shutdown"             , void (send (SendShutdown @r 44444 ExitNormally))@@ -534,7 +541,7 @@             , void               (send                 (Spawn @r-                  (void (send (ReceiveSelectedMessage @r selectAnyMessageLazy)))+                  (void (send (ReceiveSelectedMessage @r selectAnyMessage)))                 )               )             )@@ -570,7 +577,7 @@               )             )           , ( "sending"-            , void (send (SendMessage @r 44444 (Dynamic.toDyn ("test message"::String))))+            , void (send (SendMessage @r 44444 (toStrictDynamic ("test message"::String))))             )           , ( "sending shutdown"             , void (send (SendShutdown @r 44444 ExitNormally))@@ -580,7 +587,7 @@             , void               (send                 (Spawn @r-                  (void (send (ReceiveSelectedMessage @r selectAnyMessageLazy)))+                  (void (send (ReceiveSelectedMessage @r selectAnyMessage)))                 )               )             )@@ -630,7 +637,7 @@         me    <- self         other <- spawn           (do-            untilInterrupted (SendMessage @r 666666 (Dynamic.toDyn ("test"::String)))+            untilInterrupted (SendMessage @r 666666 (toStrictDynamic ("test"::String)))             void (sendMessage me ("OK"::String))           )         void (sendInterrupt other testInterruptReason)@@ -642,7 +649,7 @@         me    <- self         other <- spawn           (do-            untilInterrupted (ReceiveSelectedMessage @r selectAnyMessageLazy)+            untilInterrupted (ReceiveSelectedMessage @r selectAnyMessage)             void (sendMessage me ("OK" :: String))           )         void (sendInterrupt other testInterruptReason)
+ test/ServerForkIO.hs view
@@ -0,0 +1,110 @@+module ServerForkIO where++import           Control.Concurrent+import           Control.Eff.Extend+import           Control.Eff.State.Strict+import           Control.Eff.Concurrent+import           Control.Eff.Concurrent.Process.ForkIOScheduler+                                               as Scheduler+import           Control.Monad                  ( )+import           Test.Tasty                    hiding (Timeout)+import           Test.Tasty.HUnit+import           Common+import           Data.Typeable                 hiding ( cast )+import           Control.DeepSeq++data TestServer deriving Typeable++data instance Api TestServer x where+  TestGetStringLength :: String -> Api TestServer ('Synchronous Int)+  TestSetNextDelay :: Timeout -> Api TestServer 'Asynchronous+  deriving Typeable++instance NFData (Api TestServer x) where+  rnf (TestGetStringLength x) = rnf x+  rnf (TestSetNextDelay x) = rnf x++test_ServerCallTimeout :: TestTree+test_ServerCallTimeout =+  setTravisTestOptions+    $ testCase "Server call timeout"+    $ do+         runLift . withTraceLogging "test" local0 allLogMessages . Scheduler.schedule+               $ do  let backendDelay  = 100000+                         clientTimeout = 1000+                     s <- spawnBackend+                     linkProcess (_fromServer s)+                     logInfo "====================== All Servers Started ========================"+                     cast s (TestSetNextDelay backendDelay)+                     let testData = "this is a nice string" :: String+                         expected = 2 * length testData+                         testAction = callWithTimeout+                                       s+                                       (TestGetStringLength testData)++                     actual <- handleInterrupts+                                  (\i -> do+                                      logNotice' ("caught interrupt: " ++ show i)+                                      logNotice "adapting server delay"+                                      cast s (TestSetNextDelay clientTimeout)+                                      res <- testAction backendDelay+                                      logNotice "Yeah!! Got a result..."+                                      return (res * 2)+                                  ) +                                  (testAction clientTimeout)+                     lift (expected @=? actual)+         threadDelay 1000+++spawnRelay :: Timeout -> Server TestServer -> Eff InterruptableProcEff (Server TestServer)+spawnRelay callTimeout target = spawnApiServer hm hi+  where+    hi = InterruptCallback $ \i -> do+            logAlert' (show i)+            pure AwaitNext+    hm :: MessageCallback TestServer InterruptableProcEff+    hm = handleCastsAndCalls onCast onCall+      where+        onCast :: Api TestServer 'Asynchronous -> Eff InterruptableProcEff CallbackResult+        onCast (TestSetNextDelay x) = do+          logDebug "relaying delay"+          cast target (TestSetNextDelay x)+          pure AwaitNext++        onCall :: (NFData l, Typeable l)+               => Api TestServer ('Synchronous l)+               -> (Eff InterruptableProcEff (Maybe l, CallbackResult) -> k)+               -> k+        onCall (TestGetStringLength s) runHandler = runHandler $ do+          logDebug "relaying get string length"+          l <- callWithTimeout target (TestGetStringLength s) callTimeout+          logDebug' ("got result: " ++ show l)+          return (Just l, AwaitNext)+++spawnBackend :: Eff InterruptableProcEff (Server TestServer)+spawnBackend = spawnApiServerStateful (return (1000000 :: Timeout)) hm hi+  where+    hi = InterruptCallback $ \i -> do+            logAlert' (show i)+            pure AwaitNext+    hm :: MessageCallback TestServer (State Timeout ': InterruptableProcEff)+    hm = handleCastsAndCalls onCast onCall+      where+        onCast :: Api TestServer 'Asynchronous -> Eff (State Timeout ': InterruptableProcEff) CallbackResult+        onCast (TestSetNextDelay x) = do+          logDebug' ("setting delay: " ++ show x)+          put x+          pure AwaitNext++        onCall :: (NFData l, Typeable l)+               => Api TestServer ('Synchronous l)+               -> (Eff (State Timeout ': InterruptableProcEff) (Maybe l, CallbackResult) -> k)+               -> k+        onCall (TestGetStringLength s) runHandler = runHandler $ do+          logDebug' ("calculating string length: " ++ show s)+          t <- get+          logDebug' ("sleeping for: " ++ show t)+          lift (threadDelay (fromTimeoutMicros t))+          logDebug "sending result"+          return (Just (length s), AwaitNext)
test/SingleThreadedScheduler.hs view
@@ -7,7 +7,6 @@ import           Control.Monad import           Test.Tasty import           Test.Tasty.HUnit-import           Data.Dynamic import           Common  test_pureScheduler :: TestTree@@ -61,7 +60,7 @@                         void exitNormally                         error "This should not happen (child)!!"                     )-                sendMessage child (toDyn ("test" :: String))+                sendMessage child ("test" :: String)                 void exitNormally                 error "This should not happen!!"             )