Estou vendo um comportamento muito estranho, onde a bracket
função de Haskell está se comportando de maneira diferente, dependendo de ser stack run
ou stack test
não usada.
Considere o código a seguir, onde dois colchetes aninhados são usados para criar e limpar contêineres do 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
)
)
Quando executo isso stack run
e o interrompo Ctrl+C
, obtenho a saída esperada:
Inside both brackets, sleeping!
^CInner release
container2
Done with inner release
Outer release
container1
Done with outer release
E posso verificar se os dois contêineres do Docker são criados e removidos.
No entanto, se eu colar exatamente o mesmo código em um teste e executar stack test
, apenas (parte de) a primeira limpeza acontece:
Inside both brackets, sleeping!
^CInner release
container2
Isso resulta em um contêiner do Docker em execução na minha máquina. O que está acontecendo?
- Eu me certifiquei de que exatamente o mesmo
ghc-options
seja passado para ambos. - Repo de demonstração completo aqui: https://github.com/thomasjm/bracket-issue
.stack-work
e executá-lo diretamente, o problema não ocorrerá. Isso só acontece quando executado sob stack test
.
stack test
inicia threads de trabalho para manipular testes. 2) o manipulador SIGINT mata a rosca principal. 3) Os programas Haskell terminam quando o thread principal termina, ignorando quaisquer threads adicionais. 2 é o comportamento padrão no SIGINT para programas compilados pelo GHC. 3 é como os threads funcionam no Haskell. 1 é um palpite completo.