-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | library for transparent execution of interruptible computations -- -- Transparent support for interruptable computations. A workflow can be -- seen as a persistent thread that executes any monadic computation. -- Therefore, it can be used in very time consuming computations such are -- CPU intensive calculations or procedures that are most of the time -- waiting for the action of a process or an user, that are prone to -- comunication failures, timeouts or shutdowns. -- -- The computantion can be restarted at the interrupted point because -- such monad is encapsulated inside a state monad transformer that -- transparently checkpoint the computation state. Besides that, the -- package also provides other services associated to workflows The main -- features are: -- -- @package Workflow @version 0.5.6 -- | Transparent support for interruptable computations. A workflow can be -- seen as a persistent thread. The main features are: -- -- -- -- In this way, a very long computation that may take more time than the -- average time between hardware or software failures, shutdowns etc. The -- workflow can be defined transparently in a single monadic procedure. -- Besides state logging and recovery, there are a number of -- communication primitives that are aware of persistence across -- reinitiations such are persistent queues, persistent timeouts, or wait -- for events in the STM monad. These primitives permits inter-woikflow -- communications and communications with external threads. -- -- This package uses TCache for persistence and event handling. -- -- It also uses the package Refserialize. This package permits to reduce -- the workflow state load, since the RefSerialize package permits to -- serialize and deserialize complex and autoreferenced data structures -- without loosing such references, this is critical when big and -- structured data, such are documents, suffer little modifications -- across a set of workflow steps. Therefore, it is also recommended to -- use Refserialize for big user-defined objects that have small pieces -- that suffer little modifications during the workflow. As an added -- bonus, the history will show such changes with more detail. -- -- The step primitive is the lift operation that converts a result -- of type m a to a type Workflow m a with -- automatic state loggin and recovery. To allow such features, Every -- a must be instance of Typeable and IResource -- (defined in the TCache package). -- -- In fact, Workflow can be considered as an instance of a partial monad -- transformed. defined as such: -- --
--   class PMonadTrans  t m a  where
--   
--   plift :: Monad m => m a -> t m a
--   
--   instance  (Monad m,MonadIO m, IResource  a, Typeable a)
--   
--   => PMonadTrans (WF Stat)  m a where
--   
--   plift = step
--   
-- -- It is partial because the lift operation is not defined for every -- monad m and data type a , but for monads and data -- types that meet certain conditions. In this case, to be instances of -- MonadIO, IResource and Typeable -- respectively. -- -- to avoid to define the last two interfaces however, Read and -- Show' can be used to derive instances of IResource for -- most of the useful cases. This is the set of automatic derivations: -- --
--   (Read a, Show a) =>  Serialize a
--   
--   Typeable a => Indexable a    (a single key for all values. enough for workflows)
--   
--   (Indexable a, Serialize a) => IResource a
--   
-- -- Therefore deriving to be instance of Read, Show is enough for -- every intermediate data result along the computation -- -- Because Data.TCache.Dynamic from the package TCache -- is used for persistence, every data type must be registered by using -- registerType -- -- Here is a compkete example: This is a counter that shows a sequence of -- numbers, one a second: -- --
--   module Main where
--   import Control.Concurrent(threadDelay)
--   import System.IO (hFlush,stdout)
--   
--   count n= do
--                       putStr (show n ++  ) >> hFlush stdout >> threadDelay 1000000
--                       count (n+1)
--   
--   main= count 0
--   
-- -- This is the same program, with the added feature of remembering the -- last count after interrupted: -- --
--   module Main where
--   import Control.Workflow
--   import Control.Concurrent(threadDelay)
--   import System.IO (hFlush,stdout)
--   
--   mcount n= do
--               step $  putStr (show n ++  ) >> hFlush stdout >> threadDelay 1000000
--               mcount (n+1)
--   
--   main= do
--      registerType :: IO ()
--      registerType :: IO Int
--      let start= 0 :: Int
--      startWF  count  start   [(count, mcount)] :: IO ()
--   
-- -- This is the execution log: -- --
--   Worflow-0.5.5demos>runghc sequence.hs
--   0 1 2 3 4 5 6 7 sequence.hs: win32ConsoleHandler
--   sequence.hs: sequence.hs: interrupted
--   Worflow-0.5.5demos>
--   Worflow-0.5.5demos>runghc sequence.hs
--   7 8 9 10 11 ....
--   
module Control.Workflow type Workflow m l = WF Stat m l type WorkflowList m a b = [(String, a -> Workflow m b)] -- | Interface that must be defined for every object being cached. -- readResource and writeResource are implemented by -- default as read-write to files with its key as filename -- serialize and deserialize are specified just to allow -- these defaults. If you define your own persistence, then -- serialize and deserialize are not needed. The -- package Workflow need them anyway. -- -- minimal definition: keyResource, serialize, deserialize -- -- While serialize and deserialize are agnostic about the way of -- converison to strings, either binary or textual, treadp and tshowp use -- the monad defined in the RefSerialize package. Both ways of -- serialization are alternative. one is defined by default in terms of -- the other. the RefSerialize monad has been introduced to permit -- IResource objects to be serialized as part of larger structures that -- embody them. This is necessary for the Workdlow package. -- -- The keyResource string must be a unique since this is used to index it -- in the hash table. when accessing a resource, the user must provide a -- partial object for wich the key can be obtained. for example: -- --
--   data Person= Person{name, surname:: String, account :: Int ....)
--   
--   keyResource Person n s ...= n++s
--   
-- -- the data being accesed must have the fields used by keyResource -- filled. For example -- --
--   readResource Person {name=John, surname= Adams}
--   
-- -- leaving the rest of the fields undefined -- -- IResource has defaults definitions for all the methods except -- keyResource Either one or other serializer must be defiened for -- default witeResource, readResource and delResource class IResource a keyResource :: (IResource a) => a -> String serialize :: (IResource a) => a -> String deserialize :: (IResource a) => String -> a tshowp :: (IResource a) => a -> ST String treadp :: (IResource a) => ST a defPath :: (IResource a) => a -> String readResource :: (IResource a) => a -> IO (Maybe a) writeResource :: (IResource a) => a -> IO () delResource :: (IResource a) => a -> IO () registerType :: (DynamicInterface x) => IO x -- | PMonadTrans permits |to define a partial monad transformer. They are -- not defined for all kinds of data but the ones that have instances of -- certain classes.That is because in the lift instance code there are -- some hidden use of these classes. This also may permit an accurate -- control of effects. An instance of MonadTrans is an instance of -- PMonadTrans class PMonadTrans t m a plift :: (PMonadTrans t m a, Monad m) => m a -> t m a -- | Indexablle can be used to derive instances of IResource This is the -- set of automatic derivations: -- -- class Indexable a key :: (Indexable a) => a -> String -- | step lifts a monadic computation to the WF monad, and provides -- transparent state loging and resume of computation step :: (Monad m, MonadIO m, IResource a, Typeable a) => m a -> Workflow m a -- | start or continue a workflow. startWF :: (Monad m, MonadIO m, IResource a, Typeable a, IResource b, Typeable b) => String -> a -> WorkflowList m a b -> m b -- | re-start the non finished workflows started for all initial values -- that are listed in the workflow list restartWorkflows :: (IResource a, Typeable a, IResource b, Typeable b) => WorkflowList IO a b -> IO () getStep :: (IResource a, Typeable a, Monad m) => Int -> Workflow m a -- | return all the intermediate results. it is supposed that all the -- intermediate result have the same type. getAll :: (IResource a, Typeable a, Monad m) => WF Stat m [a] -- | log a message in the workflow history. I can be printed out with -- printWFhistory logWF :: (Monad m, MonadIO m) => String -> Workflow m () -- | return the list of object keys that are running getWFKeys :: String -> IO [String] -- | return the current state of the computation, in the IO monad getWFHistory :: (IResource a) => String -> a -> IO (Maybe Stat) -- | delete the workflow. Make sure that the workdlow is not running delWFHistory :: (IResource a) => String -> a -> IO () -- | print the state changes along the workflow, that is, all the -- intermediate results printHistory :: Stat -> IO () -- | executes a IO computation inside of the workflow monad whatever the -- monad encapsulated in the workflow. Warning: this computation is -- executed whenever the workflow restarts, no matter if it has been -- already executed previously. This is useful for intializations or -- debugging. To avoid re-execution when restarting use: step -- $ unsafeIOtoWF... -- -- To perform IO actions in a workflow that encapsulates an IO monad, use -- step over the IO action directly: -- --
--   step $ action
--   
-- -- instead of -- --
--   step $ unsafeIOtoWF $ action
--   
unsafeIOtoWF :: (Monad m) => IO a -> Workflow m a waitFor :: (IResource a, Typeable a, IResource b, Typeable b) => (b -> Bool) -> String -> a -> IO b waitUntil :: Integer -> IO () -- | wait until a certain clock time, in the STM monad. This permits to -- compose timeouts with locks waiting for data. -- -- -- --
--   flag <- getTimeoutFlag $  5 * 60
--   ap - step  .  atomically $  readQueueSTM docQueue  `orElse`  waitUntilSTM flag  > return True
--   case ap of
--           False -> logWF False or timeout >> correctWF doc
--           True -> do
--   
waitUntilSTM :: TVar Bool -> STM () -- | change the logging policy (default is syncronous) Workflow uses the -- package TCache for logging for very fast workflow steps or when TCache -- is used also for other purposes , asyncronous is a better option syncWrite :: (Monad m, MonadIO m) => Bool -> Int -> Int -> WF Stat m () -- | insert an element on top of the Queue Stack writeQueue :: (IResource a, Typeable a) => String -> a -> IO () -- | Like writeQueue, but in the STM monad writeQueueSTM :: (IResource a, Typeable a) => String -> a -> STM () -- | delete elements from the Queue stack and return them in the IO monad readQueue :: (IResource a, Typeable a) => String -> IO a -- | delete elements from the Queue stack an return them. in the STM monad readQueueSTM :: (IResource a, Typeable a) => String -> STM a unreadQueue :: (IResource a, Typeable a) => String -> a -> IO () unreadQueueSTM :: (IResource a, Typeable a) => String -> a -> STM () getTimeSeconds :: IO Integer -- | start the timeout and return the flag to be monitored by -- waitUntilSTM getTimeoutFlag :: (MonadIO m) => Integer -> Workflow m (TVar Bool) isEmptyQueue :: String -> IO Bool isEmptyQueueSTM :: String -> STM Bool instance [overlap ok] Typeable Queue instance [overlap ok] Typeable Stat instance [overlap ok] IResource Queue instance [overlap ok] Serialize Queue instance [overlap ok] Serialize Pretty instance [overlap ok] (Monad m) => Monad (WF s m) instance [overlap ok] (Monad m) => MonadIO (WF Stat m) instance [overlap ok] (MonadTrans t, Monad m) => PMonadTrans t m a instance [overlap ok] (Monad m, MonadIO m, IResource a, Typeable a) => PMonadTrans (WF Stat) m a instance [overlap ok] (Serialize a, Indexable a) => IResource a instance [overlap ok] (Typeable a) => Indexable a instance [overlap ok] IResource Stat instance [overlap ok] Serialize Stat instance [overlap ok] Serialize IDynamic