我看到一个非常奇怪的行为,其中Haskell的bracket
功能表现不同,这取决于是否stack run
或stack test
使用。
考虑以下代码,其中使用两个嵌套括号来创建和清理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是一个完整的猜测。