Browse Source

BrokerClient: handle timeout

master
Denis Tereshkin 9 years ago
parent
commit
2abd68ba2f
  1. 28
      src/ATrade/Broker/Client.hs

28
src/ATrade/Broker/Client.hs

@ -15,9 +15,11 @@ import Control.Concurrent.BoundedChan
import Control.Concurrent.MVar import Control.Concurrent.MVar
import Control.Exception import Control.Exception
import Control.Monad import Control.Monad
import Control.Monad.Loops
import Data.Aeson import Data.Aeson
import Data.Int import Data.Int
import Data.IORef import Data.IORef
import Data.Maybe
import Data.List.NonEmpty import Data.List.NonEmpty
import qualified Data.Text as T import qualified Data.Text as T
import qualified Data.ByteString.Lazy as BL import qualified Data.ByteString.Lazy as BL
@ -28,6 +30,7 @@ import System.Log.Logger
data BrokerClientHandle = BrokerClientHandle { data BrokerClientHandle = BrokerClientHandle {
tid :: ThreadId, tid :: ThreadId,
completionMvar :: MVar (), completionMvar :: MVar (),
killMvar :: MVar (),
submitOrder :: Order -> IO (Either T.Text OrderId), submitOrder :: Order -> IO (Either T.Text OrderId),
cancelOrder :: OrderId -> IO (Either T.Text ()), cancelOrder :: OrderId -> IO (Either T.Text ()),
getNotifications :: IO (Either T.Text [Notification]), getNotifications :: IO (Either T.Text [Notification]),
@ -35,32 +38,41 @@ data BrokerClientHandle = BrokerClientHandle {
respVar :: MVar BrokerServerResponse respVar :: MVar BrokerServerResponse
} }
brokerClientThread ctx ep cmd resp comp = do brokerClientThread :: Context -> T.Text -> MVar BrokerServerRequest -> MVar BrokerServerResponse -> MVar () -> MVar () -> IO ()
brokerClientThread ctx ep cmd resp comp killMv = finally brokerClientThread' cleanup
where
cleanup = putMVar comp ()
brokerClientThread' = whileM_ (isNothing <$> tryReadMVar killMv) $ do
sock <- socket ctx Req sock <- socket ctx Req
connect sock $ T.unpack ep connect sock $ T.unpack ep
finally (brokerClientThread' sock) (cleanup sock) setReceiveTimeout (restrict 1000) sock
where finally (brokerClientThread'' sock) (close sock)
cleanup sock = close sock >> putMVar comp () brokerClientThread'' sock = whileM_ (isNothing <$> tryReadMVar killMv) $ do
brokerClientThread' sock = do
forever $ do
request <- takeMVar cmd request <- takeMVar cmd
send sock [] (BL.toStrict $ encode request) send sock [] (BL.toStrict $ encode request)
events <- poll 1000 [Sock sock [In] Nothing]
if (not . null) events
then do
maybeResponse <- decode . BL.fromStrict <$> receive sock maybeResponse <- decode . BL.fromStrict <$> receive sock
case maybeResponse of case maybeResponse of
Just response -> putMVar resp response Just response -> putMVar resp response
Nothing -> putMVar resp (ResponseError "Unable to decode response") Nothing -> putMVar resp (ResponseError "Unable to decode response")
else
putMVar resp (ResponseError "Response timeout")
startBrokerClient :: Context -> T.Text -> IO BrokerClientHandle startBrokerClient :: Context -> T.Text -> IO BrokerClientHandle
startBrokerClient ctx endpoint = do startBrokerClient ctx endpoint = do
idCounter <- newIORef 1 idCounter <- newIORef 1
compMv <- newEmptyMVar compMv <- newEmptyMVar
killMv <- newEmptyMVar
cmdVar <- newEmptyMVar :: IO (MVar BrokerServerRequest) cmdVar <- newEmptyMVar :: IO (MVar BrokerServerRequest)
respVar <- newEmptyMVar :: IO (MVar BrokerServerResponse) respVar <- newEmptyMVar :: IO (MVar BrokerServerResponse)
tid <- forkIO (brokerClientThread ctx endpoint cmdVar respVar compMv) tid <- forkIO (brokerClientThread ctx endpoint cmdVar respVar compMv killMv)
return BrokerClientHandle { return BrokerClientHandle {
tid = tid, tid = tid,
completionMvar = compMv, completionMvar = compMv,
killMvar = killMv,
submitOrder = bcSubmitOrder idCounter cmdVar respVar, submitOrder = bcSubmitOrder idCounter cmdVar respVar,
cancelOrder = bcCancelOrder idCounter cmdVar respVar, cancelOrder = bcCancelOrder idCounter cmdVar respVar,
getNotifications = bcGetNotifications idCounter cmdVar respVar, getNotifications = bcGetNotifications idCounter cmdVar respVar,
@ -69,7 +81,7 @@ startBrokerClient ctx endpoint = do
} }
stopBrokerClient :: BrokerClientHandle -> IO () stopBrokerClient :: BrokerClientHandle -> IO ()
stopBrokerClient handle = yield >> killThread (tid handle) >> readMVar (completionMvar handle) stopBrokerClient handle = putMVar (killMvar handle) () >> yield >> killThread (tid handle) >> readMVar (completionMvar handle)
nextId cnt = atomicModifyIORef' cnt (\v -> (v + 1, v)) nextId cnt = atomicModifyIORef' cnt (\v -> (v + 1, v))

Loading…
Cancel
Save