我可能会设置一个接受 POST 请求的端点,而不是单个长时间运行的 GET 请求。POST 将立即返回响应正文中的两个链接:
一旦客户端成功获取任务结果资源,它就可以删除它。这应该删除任务结果资源和关联的通知资源。
对于每个 POST 请求,您都需要生成一个后台工作线程。您还需要一个后台线程来删除过时的任务结果(因为客户端可能是懒惰的并且不调用 DELETE)。这些线程将与MVar
s、TVar
s、channels或类似方法进行通信。
现在的问题是:如何最好地处理服务器发出的通知?有几种选择:
这是长轮询机制的服务器端框架。一些初步进口:
{-# LANGUAGE NumDecimals #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeApplications #-}
import Control.Concurrent (threadDelay)
import Control.Concurrent.Async (concurrently_) -- from async
import Control.Concurrent.STM -- from stm
import Control.Concurrent.STM.TMChan -- from stm-chans
import Control.Monad.IO.Class (liftIO)
import Data.Aeson (ToJSON) -- from aeson
import Data.Foldable (for_)
import Data.Text (Text)
import Web.Scotty
这是主要代码。
main :: IO ()
main =
do
chan <- atomically $ newTMChan @Text
concurrently_
( do
for_
["starting", "working on it", "finishing"]
( \msg -> do
threadDelay 10e6
atomically $ writeTMChan chan msg
)
atomically $ closeTMChan chan
)
( scotty 3000
$ get "/notifications"
$ do
mmsg <- liftIO $ atomically $ readTMChan chan
json $
case mmsg of
Nothing -> ["closed!"]
Just msg -> [msg]
)
有两个并发线程。一个以 10 秒的间隔将消息馈送到可关闭的通道,另一个运行 Scotty 服务器,每个 GET 调用都会挂起,直到有新消息到达通道。
使用curl从 bash 测试它,我们应该看到一连串的消息:
bash$ for run in {1..4}; do curl -s localhost:3000/notifications ; done
["starting"]["working on it"]["finishing"]["closed!"]