Sto vedendo un comportamento molto strano in cui la bracket
funzione di Haskell si sta comportando in modo diverso a seconda che venga utilizzata stack run
o meno stack test
.
Si consideri il codice seguente, in cui vengono utilizzate due parentesi nidificate per creare e pulire i contenitori 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 eseguo questo con stack run
e interrompo con Ctrl+C
, ottengo l'output previsto:
Inside both brackets, sleeping!
^CInner release
container2
Done with inner release
Outer release
container1
Done with outer release
E posso verificare che entrambi i contenitori Docker vengano creati e quindi rimossi.
Tuttavia, se incollo esattamente lo stesso codice in un test ed eseguo stack test
, si verifica solo (parte di) la prima pulizia:
Inside both brackets, sleeping!
^CInner release
container2
Ciò si traduce in un contenitore Docker lasciato in esecuzione sul mio computer. Cosa sta succedendo?
- Ho fatto in modo che lo stesso
ghc-options
sia passato a entrambi. - Repository dimostrativo completo qui: https://github.com/thomasjm/bracket-issue
.stack-work
e lo eseguo direttamente, il problema non si verifica. Succede solo quando corri sotto stack test
.
stack test
avvia i thread di lavoro per gestire i test. 2) il gestore SIGINT uccide il thread principale. 3) I programmi Haskell terminano quando lo fa il thread principale, ignorando eventuali thread aggiuntivi. 2 è il comportamento predefinito su SIGINT per i programmi compilati da GHC. 3 è come funzionano i thread in Haskell. 1 è un'ipotesi completa.