{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
module Langchain.Runnable.Utils
(
WithConfig (..)
, Cached (..)
, cached
, Retry (..)
, WithTimeout (..)
) where
import Control.Concurrent
import Data.Map.Strict as Map
import Langchain.Runnable.Core
data WithConfig config r
= (Runnable r) =>
WithConfig
{ forall config r. WithConfig config r -> r
configuredRunnable :: r
, forall config r. WithConfig config r -> config
runnableConfig :: config
}
instance (Runnable r) => Runnable (WithConfig config r) where
type RunnableInput (WithConfig config r) = RunnableInput r
type RunnableOutput (WithConfig config r) = RunnableOutput r
invoke :: WithConfig config r
-> RunnableInput (WithConfig config r)
-> IO (Either String (RunnableOutput (WithConfig config r)))
invoke (WithConfig r
r1 config
_) RunnableInput (WithConfig config r)
input = r -> RunnableInput r -> IO (Either String (RunnableOutput r))
forall r.
Runnable r =>
r -> RunnableInput r -> IO (Either String (RunnableOutput r))
invoke r
r1 RunnableInput r
RunnableInput (WithConfig config r)
input
data Cached r
= (Runnable r, Ord (RunnableInput r)) =>
Cached
{ forall r. Cached r -> r
cachedRunnable :: r
, forall r.
Cached r -> MVar (Map (RunnableInput r) (RunnableOutput r))
cacheMap :: MVar (Map.Map (RunnableInput r) (RunnableOutput r))
}
cached :: (Runnable r, Ord (RunnableInput r)) => r -> IO (Cached r)
cached :: forall r. (Runnable r, Ord (RunnableInput r)) => r -> IO (Cached r)
cached r
r = do
MVar (Map (RunnableInput r) (RunnableOutput r))
cache <- Map (RunnableInput r) (RunnableOutput r)
-> IO (MVar (Map (RunnableInput r) (RunnableOutput r)))
forall a. a -> IO (MVar a)
newMVar Map (RunnableInput r) (RunnableOutput r)
forall k a. Map k a
Map.empty
Cached r -> IO (Cached r)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Cached r -> IO (Cached r)) -> Cached r -> IO (Cached r)
forall a b. (a -> b) -> a -> b
$ r -> MVar (Map (RunnableInput r) (RunnableOutput r)) -> Cached r
forall r.
(Runnable r, Ord (RunnableInput r)) =>
r -> MVar (Map (RunnableInput r) (RunnableOutput r)) -> Cached r
Cached r
r MVar (Map (RunnableInput r) (RunnableOutput r))
cache
instance (Runnable r, Ord (RunnableInput r)) => Runnable (Cached r) where
type RunnableInput (Cached r) = RunnableInput r
type RunnableOutput (Cached r) = RunnableOutput r
invoke :: Cached r
-> RunnableInput (Cached r)
-> IO (Either String (RunnableOutput (Cached r)))
invoke (Cached r
r MVar (Map (RunnableInput r) (RunnableOutput r))
cacheRef) RunnableInput (Cached r)
input = do
Map (RunnableInput r) (RunnableOutput r)
cache <- MVar (Map (RunnableInput r) (RunnableOutput r))
-> IO (Map (RunnableInput r) (RunnableOutput r))
forall a. MVar a -> IO a
readMVar MVar (Map (RunnableInput r) (RunnableOutput r))
cacheRef
case RunnableInput r
-> Map (RunnableInput r) (RunnableOutput r)
-> Maybe (RunnableOutput r)
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup RunnableInput r
RunnableInput (Cached r)
input Map (RunnableInput r) (RunnableOutput r)
cache of
Just RunnableOutput r
output -> Either String (RunnableOutput r)
-> IO (Either String (RunnableOutput r))
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Either String (RunnableOutput r)
-> IO (Either String (RunnableOutput r)))
-> Either String (RunnableOutput r)
-> IO (Either String (RunnableOutput r))
forall a b. (a -> b) -> a -> b
$ RunnableOutput r -> Either String (RunnableOutput r)
forall a b. b -> Either a b
Right RunnableOutput r
output
Maybe (RunnableOutput r)
Nothing -> do
Either String (RunnableOutput r)
result <- r -> RunnableInput r -> IO (Either String (RunnableOutput r))
forall r.
Runnable r =>
r -> RunnableInput r -> IO (Either String (RunnableOutput r))
invoke r
r RunnableInput r
RunnableInput (Cached r)
input
case Either String (RunnableOutput r)
result of
Left String
err -> Either String (RunnableOutput r)
-> IO (Either String (RunnableOutput r))
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Either String (RunnableOutput r)
-> IO (Either String (RunnableOutput r)))
-> Either String (RunnableOutput r)
-> IO (Either String (RunnableOutput r))
forall a b. (a -> b) -> a -> b
$ String -> Either String (RunnableOutput r)
forall a b. a -> Either a b
Left String
err
Right RunnableOutput r
output -> do
MVar (Map (RunnableInput r) (RunnableOutput r))
-> (Map (RunnableInput r) (RunnableOutput r)
-> IO (Map (RunnableInput r) (RunnableOutput r)))
-> IO ()
forall a. MVar a -> (a -> IO a) -> IO ()
modifyMVar_ MVar (Map (RunnableInput r) (RunnableOutput r))
cacheRef ((Map (RunnableInput r) (RunnableOutput r)
-> IO (Map (RunnableInput r) (RunnableOutput r)))
-> IO ())
-> (Map (RunnableInput r) (RunnableOutput r)
-> IO (Map (RunnableInput r) (RunnableOutput r)))
-> IO ()
forall a b. (a -> b) -> a -> b
$ \Map (RunnableInput r) (RunnableOutput r)
c -> Map (RunnableInput r) (RunnableOutput r)
-> IO (Map (RunnableInput r) (RunnableOutput r))
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Map (RunnableInput r) (RunnableOutput r)
-> IO (Map (RunnableInput r) (RunnableOutput r)))
-> Map (RunnableInput r) (RunnableOutput r)
-> IO (Map (RunnableInput r) (RunnableOutput r))
forall a b. (a -> b) -> a -> b
$ RunnableInput r
-> RunnableOutput r
-> Map (RunnableInput r) (RunnableOutput r)
-> Map (RunnableInput r) (RunnableOutput r)
forall k a. Ord k => k -> a -> Map k a -> Map k a
Map.insert RunnableInput r
RunnableInput (Cached r)
input RunnableOutput r
output Map (RunnableInput r) (RunnableOutput r)
c
Either String (RunnableOutput r)
-> IO (Either String (RunnableOutput r))
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Either String (RunnableOutput r)
-> IO (Either String (RunnableOutput r)))
-> Either String (RunnableOutput r)
-> IO (Either String (RunnableOutput r))
forall a b. (a -> b) -> a -> b
$ RunnableOutput r -> Either String (RunnableOutput r)
forall a b. b -> Either a b
Right RunnableOutput r
output
data Retry r
= (Runnable r) =>
Retry
{ forall r. Retry r -> r
retryRunnable :: r
, forall r. Retry r -> Int
maxRetries :: Int
, forall r. Retry r -> Int
retryDelay :: Int
}
instance (Runnable r) => Runnable (Retry r) where
type RunnableInput (Retry r) = RunnableInput r
type RunnableOutput (Retry r) = RunnableOutput r
invoke :: Retry r
-> RunnableInput (Retry r)
-> IO (Either String (RunnableOutput (Retry r)))
invoke (Retry r
r Int
maxRetries_ Int
delay) RunnableInput (Retry r)
input = Int -> IO (Either String (RunnableOutput r))
retryWithCount Int
0
where
retryWithCount :: Int -> IO (Either String (RunnableOutput r))
retryWithCount Int
count = do
Either String (RunnableOutput r)
result <- r -> RunnableInput r -> IO (Either String (RunnableOutput r))
forall r.
Runnable r =>
r -> RunnableInput r -> IO (Either String (RunnableOutput r))
invoke r
r RunnableInput r
RunnableInput (Retry r)
input
case Either String (RunnableOutput r)
result of
Left String
err ->
if Int
count Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
maxRetries_
then do
Int -> IO ()
threadDelay Int
delay
Int -> IO (Either String (RunnableOutput r))
retryWithCount (Int
count Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1)
else Either String (RunnableOutput r)
-> IO (Either String (RunnableOutput r))
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Either String (RunnableOutput r)
-> IO (Either String (RunnableOutput r)))
-> Either String (RunnableOutput r)
-> IO (Either String (RunnableOutput r))
forall a b. (a -> b) -> a -> b
$ String -> Either String (RunnableOutput r)
forall a b. a -> Either a b
Left String
err
Right RunnableOutput r
output -> Either String (RunnableOutput r)
-> IO (Either String (RunnableOutput r))
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Either String (RunnableOutput r)
-> IO (Either String (RunnableOutput r)))
-> Either String (RunnableOutput r)
-> IO (Either String (RunnableOutput r))
forall a b. (a -> b) -> a -> b
$ RunnableOutput r -> Either String (RunnableOutput r)
forall a b. b -> Either a b
Right RunnableOutput r
output
data WithTimeout r
= (Runnable r) =>
WithTimeout
{ forall r. WithTimeout r -> r
timeoutRunnable :: r
, forall r. WithTimeout r -> Int
timeoutMicroseconds :: Int
}
instance (Runnable r) => Runnable (WithTimeout r) where
type RunnableInput (WithTimeout r) = RunnableInput r
type RunnableOutput (WithTimeout r) = RunnableOutput r
invoke :: WithTimeout r
-> RunnableInput (WithTimeout r)
-> IO (Either String (RunnableOutput (WithTimeout r)))
invoke (WithTimeout r
r Int
timeout) RunnableInput (WithTimeout r)
input = do
MVar (Maybe (Either String (RunnableOutput r)))
resultVar <- IO (MVar (Maybe (Either String (RunnableOutput r))))
forall a. IO (MVar a)
newEmptyMVar
ThreadId
tid <- IO () -> IO ThreadId
forkIO (IO () -> IO ThreadId) -> IO () -> IO ThreadId
forall a b. (a -> b) -> a -> b
$ do
Either String (RunnableOutput r)
result <- r -> RunnableInput r -> IO (Either String (RunnableOutput r))
forall r.
Runnable r =>
r -> RunnableInput r -> IO (Either String (RunnableOutput r))
invoke r
r RunnableInput r
RunnableInput (WithTimeout r)
input
MVar (Maybe (Either String (RunnableOutput r)))
-> Maybe (Either String (RunnableOutput r)) -> IO ()
forall a. MVar a -> a -> IO ()
putMVar MVar (Maybe (Either String (RunnableOutput r)))
resultVar (Either String (RunnableOutput r)
-> Maybe (Either String (RunnableOutput r))
forall a. a -> Maybe a
Just Either String (RunnableOutput r)
result)
ThreadId
timeoutTid <- IO () -> IO ThreadId
forkIO (IO () -> IO ThreadId) -> IO () -> IO ThreadId
forall a b. (a -> b) -> a -> b
$ do
Int -> IO ()
threadDelay Int
timeout
MVar (Maybe (Either String (RunnableOutput r)))
-> Maybe (Either String (RunnableOutput r)) -> IO ()
forall a. MVar a -> a -> IO ()
putMVar MVar (Maybe (Either String (RunnableOutput r)))
resultVar Maybe (Either String (RunnableOutput r))
forall a. Maybe a
Nothing
Maybe (Either String (RunnableOutput r))
result <- MVar (Maybe (Either String (RunnableOutput r)))
-> IO (Maybe (Either String (RunnableOutput r)))
forall a. MVar a -> IO a
takeMVar MVar (Maybe (Either String (RunnableOutput r)))
resultVar
ThreadId -> IO ()
killThread ThreadId
tid
ThreadId -> IO ()
killThread ThreadId
timeoutTid
case Maybe (Either String (RunnableOutput r))
result of
Just Either String (RunnableOutput r)
r_ -> Either String (RunnableOutput r)
-> IO (Either String (RunnableOutput r))
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Either String (RunnableOutput r)
r_
Maybe (Either String (RunnableOutput r))
Nothing -> Either String (RunnableOutput r)
-> IO (Either String (RunnableOutput r))
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Either String (RunnableOutput r)
-> IO (Either String (RunnableOutput r)))
-> Either String (RunnableOutput r)
-> IO (Either String (RunnableOutput r))
forall a b. (a -> b) -> a -> b
$ String -> Either String (RunnableOutput r)
forall a b. a -> Either a b
Left String
"Operation timed out"