如何在不终止 yesod-websocket 连接的情况下停止收听消息?
How to stop listening for a message without killing a yesod-websocket connection?
我正在使用 yesod-websockets
编写一个应用程序,每当我收到一条 "Start" 消息时,我需要 运行 一个不断产生数据并将其发送到客户端的线程,直到客户告诉它停止。生产者也可能会自行停止生产数据。
当生产者停止时(不管它是自己停止生产,还是客户告诉它停止),它会回到主循环并等待接收另一个 "Start" 消息。
代码看起来像这样(运行下方可实现最小重现):
wsApp :: WebSocketsT Handler ()
wsApp =
forever $ do
msg <- receiveMsg
case msg of
StartMsg -> do
race_
(produceData)
(whileM ((/= StopMsg) <$> receiveMsg))
问题是,如果produceData
自行停止,那么线程运行ning receiveMsg
将被取消,这会导致websocket连接被关闭。
21/Mar/2018:08:21:06 +0000 [Error#yesod] Exception from Warp: ConnectionClosed @(app-0.0.0-5bzI9Onrk2fFepGGsdocDz:Application src/Application.hs:122:15)
有没有办法在不终止连接的情况下取消正在侦听连接的线程?
这是一个最小的重现:
wsApp :: WebSocketsT Handler ()
wsApp = forever $ do
race_
(receiveData :: WebSocketsT Handler Text)
(pure ())
$logDebug "Trying again"
第二个线程将完成,第一个线程将被取消,导致连接被终止。
由于找不到更优雅的解决方案,我最终使用 IORef Bool
来同步 websockets 线程和生产者线程。
wsApp :: WebSocketsT Handler ()
wsApp = do
producing <- newIORef False
forever $ do
msg <- receiveMsg
case msg of
StartMsg -> do
whenM (not <$> readIORef producing) $ do
atomicWriteIORef producing True
void . async $ produceData producing
StopMsg -> atomicWriteIORef producing False
produceData :: IORef Bool -> WebSocketsT Handler ()
produceData producing =
whenM (readIORef producing) $
case produce of
Nothing -> atomicWriteIORef producing False
Just x -> sendMsg x >> produceData producing
我正在使用 yesod-websockets
编写一个应用程序,每当我收到一条 "Start" 消息时,我需要 运行 一个不断产生数据并将其发送到客户端的线程,直到客户告诉它停止。生产者也可能会自行停止生产数据。
当生产者停止时(不管它是自己停止生产,还是客户告诉它停止),它会回到主循环并等待接收另一个 "Start" 消息。
代码看起来像这样(运行下方可实现最小重现):
wsApp :: WebSocketsT Handler ()
wsApp =
forever $ do
msg <- receiveMsg
case msg of
StartMsg -> do
race_
(produceData)
(whileM ((/= StopMsg) <$> receiveMsg))
问题是,如果produceData
自行停止,那么线程运行ning receiveMsg
将被取消,这会导致websocket连接被关闭。
21/Mar/2018:08:21:06 +0000 [Error#yesod] Exception from Warp: ConnectionClosed @(app-0.0.0-5bzI9Onrk2fFepGGsdocDz:Application src/Application.hs:122:15)
有没有办法在不终止连接的情况下取消正在侦听连接的线程?
这是一个最小的重现:
wsApp :: WebSocketsT Handler ()
wsApp = forever $ do
race_
(receiveData :: WebSocketsT Handler Text)
(pure ())
$logDebug "Trying again"
第二个线程将完成,第一个线程将被取消,导致连接被终止。
由于找不到更优雅的解决方案,我最终使用 IORef Bool
来同步 websockets 线程和生产者线程。
wsApp :: WebSocketsT Handler ()
wsApp = do
producing <- newIORef False
forever $ do
msg <- receiveMsg
case msg of
StartMsg -> do
whenM (not <$> readIORef producing) $ do
atomicWriteIORef producing True
void . async $ produceData producing
StopMsg -> atomicWriteIORef producing False
produceData :: IORef Bool -> WebSocketsT Handler ()
produceData producing =
whenM (readIORef producing) $
case produce of
Nothing -> atomicWriteIORef producing False
Just x -> sendMsg x >> produceData producing