Je vois un comportement très étrange où la bracket
fonction de Haskell se comporte différemment selon qu'elle est utilisée stack run
ou non stack test
.
Considérez le code suivant, où deux crochets imbriqués sont utilisés pour créer et nettoyer les conteneurs 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
)
)
Lorsque j'exécute cela avec stack run
et que j'interromps avec Ctrl+C
, j'obtiens la sortie attendue:
Inside both brackets, sleeping!
^CInner release
container2
Done with inner release
Outer release
container1
Done with outer release
Et je peux vérifier que les deux conteneurs Docker sont créés puis supprimés.
Cependant, si je colle exactement ce même code dans un test et que j'exécute stack test
, seul (une partie de) le premier nettoyage se produit:
Inside both brackets, sleeping!
^CInner release
container2
Il en résulte un conteneur Docker laissé en cours d'exécution sur ma machine. Que se passe-t-il?
- J'ai fait en sorte que les mêmes informations
ghc-options
soient transmises aux deux. - Repo de démonstration complet ici: https://github.com/thomasjm/bracket-issue
.stack-work
et l'exécute directement, le problème ne se produit pas. Cela ne se produit que lorsque vous courez sous stack test
.
stack test
démarre les threads de travail pour gérer les tests. 2) le gestionnaire SIGINT tue le fil principal. 3) Les programmes Haskell se terminent lorsque le thread principal le fait, ignorant tous les threads supplémentaires. 2 est le comportement par défaut sur SIGINT pour les programmes compilés par GHC. 3 est la façon dont les threads fonctionnent dans Haskell. 1 est une supposition complète.