Saya melihat perilaku yang sangat aneh di mana bracket
fungsi Haskell berperilaku berbeda tergantung pada apakah stack run
atau stack test
tidak digunakan.
Pertimbangkan kode berikut, di mana dua tanda kurung bersarang digunakan untuk membuat dan membersihkan wadah 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
)
)
Ketika saya menjalankan ini dengan stack run
dan menyela dengan Ctrl+C
, saya mendapatkan hasil yang diharapkan:
Inside both brackets, sleeping!
^CInner release
container2
Done with inner release
Outer release
container1
Done with outer release
Dan saya dapat memverifikasi bahwa kedua wadah Docker dibuat dan kemudian dihapus.
Namun, jika saya menempelkan kode yang sama persis ini ke dalam pengujian dan menjalankan stack test
, hanya (bagian dari) pembersihan pertama terjadi:
Inside both brackets, sleeping!
^CInner release
container2
Ini menghasilkan wadah Docker dibiarkan berjalan di mesin saya. Apa yang sedang terjadi?
- Saya sudah memastikan bahwa hal yang sama
ghc-options
diteruskan ke keduanya. - Repo demonstrasi lengkap di sini: https://github.com/thomasjm/bracket-issue
.stack-work
dan menjalankannya langsung, maka masalahnya tidak terjadi. Itu hanya terjadi ketika berjalan di bawah stack test
.
stack test
memulai utas pekerja untuk menangani tes. 2) pengendali SIGINT membunuh utas utama. 3) Program Haskell berakhir ketika utas utama tidak, mengabaikan utas tambahan. 2 adalah perilaku default pada SIGINT untuk program yang dikompilasi oleh GHC. 3 adalah cara kerja utas di Haskell. 1 adalah tebakan lengkap.