Haskellのbracket
関数が、stack run
またはstack test
が使用されているかどうかによって異なる動作をするという非常に奇妙な動作を目にしています。
次のコードを検討してください。ネストされた2つのブラケットがDockerコンテナの作成とクリーンアップに使用されています。
module Main where
import Control.Concurrent
import Control.Exception
import System.Process
main :: IO ()
main = do
bracket (callProcess "docker" ["run", "-d", "--name", "container1", "registry:2"])
(\() -> do
putStrLn "Outer release"
callProcess "docker" ["rm", "-f", "container1"]
putStrLn "Done with outer release"
)
(\() -> do
bracket (callProcess "docker" ["run", "-d", "--name", "container2", "registry:2"])
(\() -> do
putStrLn "Inner release"
callProcess "docker" ["rm", "-f", "container2"]
putStrLn "Done with inner release"
)
(\() -> do
putStrLn "Inside both brackets, sleeping!"
threadDelay 300000000
)
)
これをで実行しstack run
、で中断するとCtrl+C
、予期した出力が得られます。
Inside both brackets, sleeping!
^CInner release
container2
Done with inner release
Outer release
container1
Done with outer release
そして、両方のDockerコンテナーが作成されてから削除されていることを確認できます。
ただし、このまったく同じコードをテストに貼り付けて実行するstack test
と、最初のクリーンアップ(の一部)のみが発生します。
Inside both brackets, sleeping!
^CInner release
container2
これにより、Dockerコンテナーが私のマシンで実行されたままになります。どうしたの?
- まったく同じ
ghc-options
ものが両方に渡されることを確認しました。 - ここで完全なデモのリポジトリ:https : //github.com/thomasjm/bracket-issue
.stack-work
て直接実行した場合、問題は発生しません。で実行してstack test
いるときにのみ発生します。
stack test
テストを処理するためにワーカースレッドを開始します。2)SIGINTハンドラーがメインスレッドを強制終了します。3)メインスレッドが終了すると、Haskellプログラムは終了し、追加のスレッドは無視されます。2は、GHCによってコンパイルされたプログラムのSIGINTでのデフォルトの動作です。3は、Haskellでスレッドが機能する方法です。1は完全な推測です。