Try
Purpose
Section titled “Purpose”The Try
task provides robust error handling and optional retry mechanisms within a workflow. It allows you to attempt
the execution of a block of tasks and define how to react if an error occurs during that execution.
It’s primarily used for:
- Gracefully catching specific errors raised by tasks within the
try
block. - Executing alternative compensation or cleanup tasks when an error is caught (using the
catch.do
block). - Implementing automatic retries for transient errors (like network timeouts or temporary service unavailability) with configurable delays, backoff strategies, and limits.
- Preventing specific errors from halting the entire workflow.
Basic Usage
Section titled “Basic Usage”Here’s a simple example of trying to call an external service and catching a potential communication error:
document: dsl: '1.0.0' namespace: examples name: try-catch-basic version: '1.0.0'do: - attemptServiceCall: try: # Tasks to attempt inside the 'try' block (must be a list) - callMyApi: call: http # See [HTTP Call Task](/docs/call-tasks/http/) for details with: method: get uri: https://api.unreliable.com/data # This call might fail with a communication error catch: # Define how to handle errors caught from the 'try' block errors: # Catch specific error types (optional) with: type: https://serverlessworkflow.io/spec/1.0.0/errors/communication as: "apiError" # Store the caught error details in $apiError variable (default is $error) do: # Tasks to execute ONLY if an error matching the filter is caught - logFailure: call: log with: level: "warn" message: "API call failed. Error: ${ $apiError }" - setDefaultValue: set: # Provide a default output if the try block failed data: null status: "failed" - continueProcessing: # Executes after attemptServiceCall (either success or caught error) # Input is the output of 'callMyApi' if successful, # or the output of 'setDefaultValue' if an error was caught. # ...
In this example, if callMyApi
fails with a standard communication
error, the catch
block is activated. The error
details are stored in the $apiError
variable (accessible within the catch.do
block), the failure is logged, and a
default output is set. Execution then proceeds normally to continueProcessing
. If callMyApi
succeeds, the catch
block is skipped entirely.
Here’s an example demonstrating automatic retries:
do: - attemptWithRetry: try: - fetchCrucialData: call: http with: # ... service details ... # Might temporarily fail with 503 catch: errors: with: status: 503 # Only catch 'Service Unavailable' errors retry: delay: PT2S # Initial delay 2 seconds backoff: exponential: { } # Exponential backoff (2s, 4s, 8s...) limit: attempt: count: 4 # Max 1 initial attempt + 3 retries = 4 total # No 'catch.do' means if all retries fail, the error is re-thrown - processData: # Only reached if fetchCrucialData succeeds eventually # ...
This example attempts fetchCrucialData
. If it fails with a 503 status, it waits 2 seconds and retries. If it fails
again, it waits 4 seconds, then 8 seconds. If it still fails after the 4th total attempt, the 503 error is not
caught (because there’s no catch.do
), and the workflow likely faults unless a parent Try
catches it.
Configuration Options
Section titled “Configuration Options”try
(List<String, Object>, Required)
Section titled “try (List<String, Object>, Required)”This mandatory property contains a list defining the sequence of tasks to be attempted.
If any task within this block raises an error, the runtime checks the corresponding catch
block to see if the error
should be handled.
catch
(Object, Required)
Section titled “catch (Object, Required)”This mandatory object defines how errors originating from the try
block are handled.
For an error raised in the try
block to be considered “caught” by this catch
block, it must sequentially pass all applicable filters in this order:
- Match
errors.with
: Iferrors.with
is defined, the error’s properties must exactly match all specified criteria. - Pass
when
: Ifwhen
is defined, its runtime expression (evaluated against the error, accessible via the variable named inas
) must returntrue
. - Pass
exceptWhen
: IfexceptWhen
is defined, its runtime expression (evaluated against the error) must returnfalse
. retry
is configured and attempts are not exhausted (thetry
task is then retried) ORcatch.do
is defined (thecatch.do
is then processed).
The catch
block can contain the following properties:
-
errors
(Object, Optional): Filters which errors are potentially caught.with
: (Object, Optional) Defines specific properties that an error raised within thetry
block must have to be considered for catching by thiscatch
block. This allows for fine-grained filtering based on the error’s characteristics.- You can specify one or more standard Error object
fields:
type
,status
,instance
,title
,details
. - Matching Logic: An incoming error matches the
with
filter only if all fields specified within thewith
object exactly match the corresponding fields in the raised error object. It acts as a logical AND condition. - If the
with
object is omitted, this specific property-based filtering step is skipped, and all errors are considered potentially catchable (subject to further filtering bywhen
/exceptWhen
). - Example:
catch:errors:with:# Only catch errors of this specific type AND statustype: "https://serverlessworkflow.io/spec/1.0.0/errors/communication"status: 503# instance: /do/0/callApi # Optionally match instance too# ... other catch properties (as, when, retry, do) ...
- You can specify one or more standard Error object
fields:
-
as
(String, Optional): Specifies the variable name used to store the caught error object within the scope of thecatch
block (when
,exceptWhen
,retry
,do
). Defaults toerror
(accessible as$error
in expressions). -
when
(String, Optional): A Runtime Expression evaluated if an error matches theerrors.with
filter. The expression has access to the caught error via the variable named byas
. The error is only caught if this expression evaluates totrue
.- Example: Catch communication errors only if they occurred for a specific instance:
catch:errors:with: { type: ".../communication" }as: "commErr" # Optional, using 'commErr' instead of default 'error'when: "${ $commErr.instance == '/do/0/unreliableApiCall' }"# ... retry or do ...
- Example: Catch communication errors only if they occurred for a specific instance:
-
exceptWhen
(String, Optional): A Runtime Expression evaluated if an error matches theerrors.with
filter and thewhen
condition (if present) was true. The expression has access to the caught error. The error is not caught if this expression evaluates totrue
.-
Example: Catch all validation errors except those related to a specific field:
catch:errors:with: { type: ".../validation" }# Uses default 'error' variable -> $errorexceptWhen: "${ $error.details | contains(\"userEmail\" }" # Don't catch if details mention userEmaildo:# Handle other validation errors -
retry
(String | Object, Optional): Defines the retry strategy if an error is caught (passes filters). Can be a string referencing a namedRetryPolicy
defined inworkflow.use.retries
, or an inlineRetryPolicy
object.when
/exceptWhen
(String, Optional): Runtime expressions evaluated before calculating the retry delay to conditionally decide if a retry should occur for the caught error.delay
(String | Object, Required in Policy): Base delay before the first retry (ISO 8601 Duration or object like{ seconds: 5 }
).backoff
(Object, Optional): Strategy for increasing delay between retries.constant: {}
: No increase (default ifbackoff
omitted).linear: {}
: Delay increases linearly (delay * (1 + attemptIndex)).exponential: {}
: Delay increases exponentially (delay ^ (1 + attemptIndex)).
limit
(Object, Optional): Defines limits for retrying.attempt
: (Object, Optional) Limits related to individual attempts.count
(Integer, Optional): The maximum number of total attempts allowed (the initial attempt plus all retries). If this limit is reached, retrying stops.duration
(String | Object - Duration, Optional): The maximum allowed duration for any single attempt ( initial or retry), measured from the start of that specific attempt’s execution until its completion ( success or error). If any individual attempt exceeds this duration, it’s considered a failure ( potentially triggering aTimeout
error or the next retry if attempts remain), even if the overall retry duration limit (limit.duration
) hasn’t been reached. This duration does not include thedelay
time preceding the attempt.
duration
(String | Object - Duration, Optional): The maximum total duration allowed for the entire retry process, measured from the start of the initial attempt and encompassing all subsequent attempt execution times and the delay periods between them. If this overall duration is exceeded, retrying stops immediately, even if the attempt count (limit.attempt.count
) hasn’t been reached.
jitter
(Object, Optional): Introduces randomness to the retry delay to help prevent simultaneous retries from multiple workflow instances causing a “thundering herd” problem on downstream services. Contains the following properties:from
(duration
, Required): The minimum duration value for the random jitter range.to
(duration
, Required): The maximum duration value for the random jitter range.- How it works: After the base delay (and any backoff multiplication) is calculated, a random duration
chosen uniformly from the range [
from
,to
] (inclusive) is added to it. The actual delay before the next retry will becalculated_delay + random(jitter.from, jitter.to)
. - Example: If the calculated delay (after backoff) is 10 seconds and
jitter
is{ from: { seconds: 1 }, to: { seconds: 3 } }
, the actual delay before the next retry will be a random value between 11.0 and 13.0 seconds.
Examples
Section titled “Examples”1. Simple Retry Count: Retry up to 3 times with a fixed 5-second delay.
retry:delay: { seconds: 5 }limit:attempt:count: 4 # 1 initial + 3 retries2. Linear Backoff with Total Duration Limit: Retry with delay increasing linearly (2s, 4s, 6s…), stopping after a total of 1 minute.
retry:delay: { seconds: 2 }backoff:linear: { }limit:duration: { minutes: 1 }3. Exponential Backoff with Jitter: Retry with exponentially increasing delay (1s, 2s, 4s…) plus random jitter between 0.5 and 1.5 seconds.
retry:delay: { seconds: 1 }backoff:exponential: { }jitter:from: { milliseconds: 500 }to: { seconds: 1, milliseconds: 500 }limit:attempt:count: 54. Conditional Retry: Only retry if the error details mention a timeout, using the default error variable
$error
.retry:when: "${ $error.details | contains(\"timeout\") }" # Only retry on timeoutsdelay: { seconds: 10 }limit:attempt:count: 3
-
-
do
(List<String, Object>, Optional): A block of tasks to execute sequentially only if an error is successfully caught (passeserrors.with
,when
, andexceptWhen
filters).- Output: If the
catch.do
block executes, its final transformed output becomes therawOutput
of the entireTry
task. - Omission: If
catch.do
is omitted and retries are exhausted, the error propagates upwards.
If a
retry
policy is also defined for the caught error, thecatch.do
block will only execute if all retry attempts are exhausted without success.- If any retry attempt succeeds, the
catch.do
block is skipped entirely, theTry
task completes successfully using the output of the successful retry attempt, and execution proceeds via theTry
task’sthen
directive. - If all retries fail (due to limits or persistent errors), then the
catch.do
block (if present) is executed.
- Output: If the
Data Flow
Section titled “Data Flow”This task supports standard configuration for the Data Flow
(including input
, output
, export
, and schemas).
Refer to those pages for details on these common properties and how they apply generally.
Note on Try
Data Flow:
- The
rawOutput
used byoutput.as
andexport.as
is determined as follows:- If the
try
block completes successfully,rawOutput
is thetransformedOutput
of the last task withintry
. - If an error is caught and handled by executing the
catch.do
block,rawOutput
is thetransformedOutput
of the last task withincatch.do
. - If an error is caught, retries are exhausted (or not configured), and there is no
catch.do
block, the error propagates upwards. TheTry
task does not produce an output in this case, as it doesn’t complete successfully.
- If the
Flow Control
Section titled “Flow Control”This task supports standard configuration for the Flow Control
(including conditional execution with if
and branching with then
).
Refer to those pages for details on these common properties and how they apply generally.
Note on Try
Flow Control:
- The
Try
task’sthen
directive is followed if and only if the task completes successfully. Successful completion occurs under these conditions:- The
try
block finishes without raising any error that is caught by thecatch
filters. - An error is caught, a
retry
policy is triggered, and any retry attempt succeeds. - An error is caught, all
retry
attempts (if configured) are exhausted without success, and thecatch.do
block (if present) executes successfully.
- The
- In all other scenarios, the
Try
task does not complete successfully, and itsthen
directive is not followed. This includes:- An error raised in
try
that is not caught by thecatch
filters. - An error that is caught, exhausts all retries (or has no retry policy), and has no
catch.do
block to handle it (the error propagates). - The
catch.do
block itself raises an error.
- An error raised in