我编写了一个小型服务器,它接受作为 POST 请求的注册并通过将它们附加到文件来持久化它们。一旦我将此服务器置于负载状态(我使用具有 50 个并发线程和 10 个重复计数的 Apache JMeter,并且帖子包含一个包含约 7k 文本数据的字段),我就会得到很多“资源繁忙,文件是锁定”错误:
02/Nov/2013:18:07:11 +0100 [Error#yesod-core] registrations.txt: openFile: resource busy (file is locked) @(yesod-core-1.2.4.2:Yesod.Core.Class.Yesod ./Yesod/Core/Class/Yesod.hs:485:5)
这是代码的精简版本:
{-# LANGUAGE QuasiQuotes, TemplateHaskell, MultiParamTypeClasses, OverloadedStrings, TypeFamilies #-}
import           Yesod
import           Text.Hamlet
import           Control.Applicative ((<$>), (<*>))
import           Control.Monad.IO.Class (liftIO)
import           Data.Text (Text, pack, unpack)
import           Data.String
import           System.IO (withFile, IOMode(..), hPutStrLn)
data Server = Server
data Registration = Registration
        { text      :: Text
        }
    deriving (Show, Read)
mkYesod "Server" [parseRoutes|
/reg    RegR    POST
|]
instance Yesod Server
instance RenderMessage Server FormMessage where
    renderMessage _ _ = defaultFormMessage
postRegR :: Handler Html
postRegR = do
    result <- runInputPost $ Registration
        <$> ireq textField "text"
    liftIO $ saveRegistration result
    defaultLayout [whamlet|<p>#{show result}|]
saveRegistration :: Registration -> IO ()
saveRegistration r = withFile "registrations.txt" AppendMode (\h -> hPutStrLn h $ "+" ++ show r)
main :: IO ()
main = warp 8080 Server
我故意编译了没有 的代码-threaded,并且操作系统只显示一个正在运行的线程。尽管如此,在我看来,请求并没有完全序列化,并且在旧请求写入磁盘之前已经处理了一个新请求。
您能告诉我如何避免错误消息并确保成功处理所有请求吗?性能还不是问题。