Я написал небольшой сервер, который принимает регистрации как POST-запросы и сохраняет их, добавляя их в файл. Как только я нагружаю этот сервер (я использую Apache JMeter с 50 одновременными потоками и числом повторений 10, а сообщение состоит из одного поля с ~ 7 КБ текстовых данных), я получаю много «ресурс занят, файл заблокировано» ошибки:
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
, и ОС показывает только один запущенный поток. Тем не менее, мне кажется, что запросы не полностью сериализованы, и новый запрос уже обрабатывается до того, как старый был записан на диск.
Не могли бы вы сказать мне, как я могу избежать сообщения об ошибке и убедиться, что все запросы обрабатываются успешно? Производительность пока не проблема.