Я бачу дуже дивна поведінка , де Хаскелл 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 - поведінка SIGINT за замовчуванням для програм, складених GHC. 3, як працюють нитки в Haskell. 1 - повна здогадка.