ฉันเห็นพฤติกรรมแปลก ๆ ที่bracketหน้าที่ของ Haskell ทำงานแตกต่างกันไปขึ้นอยู่กับว่ามีการใช้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นั้นถูกส่งผ่านไปยังทั้งคู่ - repo สาธิตเต็มรูปแบบที่นี่: https://github.com/thomasjm/bracket-issue
.stack-workรันและรันโดยตรงปัญหาจะไม่เกิดขึ้น stack testมันจะเกิดขึ้นเมื่อมีการทำงานภายใต้
stack testเริ่มเธรดผู้ปฏิบัติงานเพื่อจัดการทดสอบ 2) ตัวจัดการ SIGINT ฆ่าเธรดหลัก 3) โปรแกรม Haskell จะสิ้นสุดเมื่อเธรดหลักทำโดยไม่สนใจเธรดเพิ่มเติมใด ๆ 2 คือพฤติกรรมเริ่มต้นบน SIGINT สำหรับโปรแกรมที่รวบรวมโดย GHC 3 คือการทำงานของเธรดใน Haskell 1 เป็นการเดาที่สมบูรณ์