Я бачу дуже дивна поведінка , де Хаскелл 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 - повна здогадка.