core-program 0.6.9.4 → 0.7.0.0
raw patch · 3 files changed
+72/−18 lines, 3 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ Core.Program.Execute: instance GHC.Exception.Type.Exception Core.Program.Execute.InvalidState
+ Core.Program.Execute: instance GHC.Show.Show Core.Program.Execute.InvalidState
- Core.Program.Execute: invalid :: Program τ α
+ Core.Program.Execute: invalid :: HasCallStack => Program τ α
Files
- core-program.cabal +1/−1
- lib/Core/Program/Execute.hs +19/−4
- lib/Core/Program/Threads.hs +52/−13
core-program.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack name: core-program-version: 0.6.9.4+version: 0.7.0.0 synopsis: Opinionated Haskell Interoperability description: A library to help build command-line programs, both tools and longer-running daemons.
lib/Core/Program/Execute.hs view
@@ -177,6 +177,7 @@ import Data.List qualified as List (intersperse) import GHC.Conc (getNumProcessors, numCapabilities, setNumCapabilities) import GHC.IO.Encoding (setLocaleEncoding, utf8)+import GHC.Stack (HasCallStack) import System.Directory ( findExecutable )@@ -1120,7 +1121,7 @@ @since 0.5.1 -}-queryOptionValue' :: Externalize ξ => LongName -> Program τ (Maybe ξ)+queryOptionValue' :: (Externalize ξ) => LongName -> Program τ (Maybe ξ) queryOptionValue' name = do context <- ask let params = commandLineFrom context@@ -1189,7 +1190,7 @@ @since 0.6.2 -}-queryEnvironmentValue' :: Externalize ξ => LongName -> Program τ (Maybe ξ)+queryEnvironmentValue' :: (Externalize ξ) => LongName -> Program τ (Maybe ξ) queryEnvironmentValue' name = do context <- ask let params = commandLineFrom context@@ -1229,8 +1230,22 @@ Nothing -> error "Attempted lookup of command but not a Complex Config" {- |+Exception thrown by 'invalid'. It's not meant to be caught and so is not+exposed publicly.++@since 0.6.10+-}+data InvalidState = InvalidState+ deriving (Show)++instance Exception InvalidState++{- | Illegal internal state resulting from what should be unreachable code or otherwise a programmer error. -}-invalid :: Program τ α-invalid = error "Invalid State"+invalid :: (HasCallStack) => Program τ α+invalid = do+ critical "Invalid state reached"+ write "error: invalid state"+ terminate 99
lib/Core/Program/Threads.hs view
@@ -126,24 +126,72 @@ 'Program', including sharing the user-defined application state value. If you want to find out what the result of a thread was use 'waitThread' on-the 'Thread' object returned from this function. If you don't need the-result, use 'forkThread_' instead.+the 'Thread' object returned from this function. For example: +@+ t1 <- 'forkThread' $ do+ 'Core.Program.Logging.info' \"Doing interesting stuff concurrently\"+ 'pure' True++ ...++ result <- 'waitThread' t1++ if result+ then -- expected+ else -- not good+@++If you don't need the result, you can use 'forkThread_' instead.+ Threads that are launched off as children are on their own! If the code in the child thread throws an exception that is /not/ caught within that thread, the exception will kill the thread. Threads dying without telling anyone is a bit of an anti-pattern, so this library logs a warning-level log message if this happens. -(this wraps __base__'s 'Control.Concurrent.forkIO')+(this function wraps __base__'s 'Control.Concurrent.forkIO') +/Concerning telemetry/++Note that threads inherit the telemetry state from their parent. If you are+using the tracing features from __core-telemetry__ any telemetry registered in+that side task will be included in the enclosing span active in the parent+thread that spawned the thread:++@+ t2 <- 'forkThread' $ do+ 'Core.Program.Logging.info' \"Performing quick side task\"+ 'Core.Telemetry.Observability.telemetry'+ [ ''Core.Telemetry.Observability.metric' \"counter\" 42+ ]+ ...++@++In this case the @\"counter\"@ field in the parent thread's current span will+get the value @42@. This is appropriate for the common case where you are doing+small side tasks concurrently to accelerate a larger computation.++But at other times you are launching off a fully independent control flow and+want it to have its own telemetry. In those cases, you'll want to start a new+span (or even a new trace) immediately after forking the thread:++@+ 'forkThread_' $ do+ 'Core.Telemetry.Observability.encloseSpan' \"subTask\" $ do+ ...+@++any telemetry from this worker thread will be appropriately nested in a new+child span called @\"subTask\"@.+ @since 0.2.7 -} forkThread :: Program τ α -> Program τ (Thread α) forkThread program = do context <- ask let i = startTimeFrom context- let v = currentDatumFrom context let scope = currentScopeFrom context liftIO $ do@@ -154,18 +202,9 @@ start <- readMVar i i' <- newMVar start - -- we also need to fork the current Datum, in the same way that we do- -- when we create a nested span. We do this simply by creating a new- -- MVar so that when the new thread updates the attached metadata- -- it'll be evolving a different object.-- datum <- readMVar v- v' <- newMVar datum- let context' = context { startTimeFrom = i'- , currentDatumFrom = v' } -- fork, and run nested program