Skip to content

Commit e97836a

Browse files
iand675claude
andauthored
Add cancel function to Temporal.Client (#247)
Expose the requestCancelWorkflowExecution gRPC call as a high-level cancel function that allows graceful workflow cancellation. Unlike terminate, cancellation is cooperative and requires the workflow to check for it. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude <[email protected]>
1 parent b3540e2 commit e97836a

File tree

1 file changed

+42
-1
lines changed

1 file changed

+42
-1
lines changed

sdk/src/Temporal/Client.hs

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ module Temporal.Client (
4040
-- * Closing Workflows
4141
TerminationOptions (..),
4242
terminate,
43+
CancellationOptions (..),
44+
cancel,
4345

4446
-- * Querying Workflows
4547
QueryOptions (..),
@@ -154,7 +156,7 @@ import Temporal.Payload
154156
import Temporal.SearchAttributes.Internal
155157
import Temporal.Workflow (KnownQuery (..), KnownSignal (..), QueryRef (..))
156158
import Temporal.Workflow.Definition
157-
import UnliftIO
159+
import UnliftIO hiding (cancel)
158160
import Unsafe.Coerce
159161

160162

@@ -804,6 +806,45 @@ terminate h req =
804806
& RR.firstExecutionRunId .~ maybe "" rawRunId h.workflowHandleFirstExecutionRunId
805807

806808

809+
data CancellationOptions = CancellationOptions
810+
{ cancellationReason :: Text
811+
}
812+
813+
814+
{- | Canceling a workflow sends a cancellation request to the workflow. Unlike
815+
'terminate', cancellation is cooperative - the workflow must check for cancellation
816+
and react to it. The workflow can perform cleanup operations when it detects the
817+
cancellation request.
818+
819+
The workflow will only transition to a canceled state if it explicitly checks for
820+
and handles the cancellation. If the workflow does not check for cancellation, it
821+
will continue running normally.
822+
-}
823+
cancel :: (MonadIO m) => WorkflowHandle a -> CancellationOptions -> m ()
824+
cancel h req =
825+
void do
826+
res <-
827+
liftIO $
828+
requestCancelWorkflowExecution
829+
h.workflowHandleClient.clientCore
830+
msg
831+
case res of
832+
Left err -> throwIO $ Temporal.Exception.coreRpcErrorToRpcError err
833+
Right _ -> pure ()
834+
where
835+
msg =
836+
defMessage
837+
& RR.namespace .~ rawNamespace h.workflowHandleClient.clientConfig.namespace
838+
& RR.workflowExecution
839+
.~ ( defMessage
840+
& Common.workflowId .~ rawWorkflowId h.workflowHandleWorkflowId
841+
& Common.runId .~ maybe "" rawRunId h.workflowHandleRunId
842+
)
843+
& RR.reason .~ req.cancellationReason
844+
& RR.identity .~ Core.identity (Core.clientConfig h.workflowHandleClient.clientCore)
845+
& RR.firstExecutionRunId .~ maybe "" rawRunId h.workflowHandleFirstExecutionRunId
846+
847+
807848
data FollowOption = FollowRuns | ThisRunOnly
808849

809850

0 commit comments

Comments
 (0)