-
Notifications
You must be signed in to change notification settings - Fork 15
docs: add conditional steps documentation and skipped step styling #594
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: 01-05-condition
Are you sure you want to change the base?
Conversation
🦋 Changeset detectedLatest commit: 096d008 The changes in this PR will be included in the next version bump. This PR includes changesets to release 5 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
Warning This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
This stack of pull requests is managed by Graphite. Learn more about stacking. |
|
View your CI Pipeline Execution ↗ for commit 096d008
☁️ Nx Cloud last updated this comment at |
1d9f0cf to
8cfa234
Compare
44482fc to
12c7537
Compare
8cfa234 to
45fa698
Compare
45fa698 to
44a7cad
Compare
44a7cad to
117e766
Compare
12c7537 to
963cad9
Compare
117e766 to
56ec88e
Compare
56ec88e to
844ba94
Compare
844ba94 to
11417a0
Compare
pkgs/website/src/content/docs/reference/configuration/step-execution.mdx
Outdated
Show resolved
Hide resolved
| ## Conditional Execution Options | ||
|
|
||
| These options control which steps execute based on input patterns and how failures are handled. See [Conditional Steps](/build/conditional-steps/) for detailed explanations and examples. | ||
|
|
||
| ### `if` | ||
|
|
||
| **Type:** `ContainmentPattern<Input>` | ||
| **Default:** Not applicable (must be explicitly set) | ||
|
|
||
| Run the step only if input contains the specified pattern. pgflow uses PostgreSQL's `@>` containment operator for matching. | ||
|
|
||
| ```typescript | ||
| // Root step - checks flow input | ||
| .step({ | ||
| slug: 'premiumFeature', | ||
| if: { plan: 'premium' }, // Only run for premium users | ||
| }, handler) | ||
|
|
||
| // Dependent step - checks dependency output | ||
| .step({ | ||
| slug: 'notify', | ||
| dependsOn: ['analyze'], | ||
| if: { analyze: { needsAlert: true } }, // Check analyze output | ||
| }, handler) | ||
| ``` | ||
|
|
||
| <Aside type="note"> | ||
| The pattern type `ContainmentPattern<Input>` matches the input shape: | ||
| - Root steps: Pattern is checked against flow input | ||
| - Dependent steps: Pattern is checked against object `{ depSlug: depOutput, ... }` | ||
| </Aside> | ||
|
|
||
| ### `ifNot` | ||
|
|
||
| **Type:** `ContainmentPattern<Input>` | ||
| **Default:** Not applicable (must be explicitly set) | ||
|
|
||
| Run the step only if input does NOT contain the specified pattern. | ||
|
|
||
| ```typescript | ||
| .step({ | ||
| slug: 'standardUserFlow', | ||
| ifNot: { role: 'admin' }, // Skip admin users | ||
| }, handler) | ||
| ``` | ||
|
|
||
| You can combine `if` and `ifNot` - both conditions must be satisfied: | ||
|
|
||
| ```typescript | ||
| .step({ | ||
| slug: 'targetedNotification', | ||
| if: { status: 'active' }, // Must be active | ||
| ifNot: { role: 'admin' }, // AND must not be admin | ||
| }, handler) | ||
| ``` | ||
|
|
||
| ### `whenUnmet` | ||
|
|
||
| **Type:** `'fail' | 'skip' | 'skip-cascade'` | ||
| **Default:** `'skip'` | ||
|
|
||
| Controls what happens when `if` or `ifNot` condition is not met. | ||
|
|
||
| | Mode | Behavior | | ||
| | ---------------- | ------------------------------------------------------------------------------- | | ||
| | `'fail'` | Step fails, entire run fails | | ||
| | `'skip'` | Step marked as skipped, run continues, dependents receive `undefined` (default) | | ||
| | `'skip-cascade'` | Step AND all downstream dependents skipped, run continues | | ||
|
|
||
| ```typescript | ||
| .step({ | ||
| slug: 'enrichData', | ||
| if: { includeEnrichment: true }, | ||
| whenUnmet: 'skip', // Default - could be omitted | ||
| }, handler) | ||
|
|
||
| .step({ | ||
| slug: 'criticalPath', | ||
| if: { plan: 'premium' }, | ||
| whenUnmet: 'fail', // Explicit - fail if not premium | ||
| }, handler) | ||
| ``` | ||
|
|
||
| <Aside type="tip"> | ||
| The default of `'skip'` means steps with conditions automatically continue the | ||
| workflow rather than failing the entire run. | ||
| </Aside> | ||
|
|
||
| ### `retriesExhausted` | ||
|
|
||
| **Type:** `'fail' | 'skip' | 'skip-cascade'` | ||
| **Default:** `'fail'` | ||
|
|
||
| Controls what happens when a step fails after exhausting all `maxAttempts` retry attempts. | ||
|
|
||
| | Mode | Behavior | | ||
| | ---------------- | --------------------------------------------------------------------- | | ||
| | `'fail'` | Step fails, entire run fails (default) | | ||
| | `'skip'` | Step marked as skipped, run continues, dependents receive `undefined` | | ||
| | `'skip-cascade'` | Step AND all downstream dependents skipped, run continues | | ||
|
|
||
| ```typescript | ||
| .step({ | ||
| slug: 'sendEmail', | ||
| maxAttempts: 3, | ||
| retriesExhausted: 'skip', // Don't fail run if email service is down | ||
| }, handler) | ||
|
|
||
| .step({ | ||
| slug: 'criticalOperation', | ||
| maxAttempts: 5, | ||
| retriesExhausted: 'fail', // Default - fail if operation fails | ||
| }, handler) | ||
| ``` | ||
|
|
||
| <Aside type="tip"> | ||
| Use `retriesExhausted: 'skip'` for non-critical steps like notifications, | ||
| analytics, or optional enrichment. | ||
| </Aside> | ||
|
|
||
| <Aside type="caution" title="TYPE_VIOLATION Errors"> | ||
| Programming errors like returning wrong type (e.g., string instead of array | ||
| for map step) always fail the run, regardless of `retriesExhausted` setting. | ||
| These are bugs in your code, not runtime conditions. >>>>>>> 153eae64 (add | ||
| docs for conditional steps) | ||
| </Aside> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Complete duplication of the "Conditional Execution Options" section. Lines 268-393 are an exact duplicate of lines 142-267, which will cause confusing documentation with repeated content. The entire duplicated section should be removed.
- ## Conditional Execution Options
-
- These options control which steps execute based on input patterns and how failures are handled. See [Conditional Steps](/build/conditional-steps/) for detailed explanations and examples.
-
- ### `if`
- ...
- (remove all duplicate content from lines 268-393)Spotted by Graphite Agent
Is this helpful? React 👍 or 👎 to let us know.
pkgs/website/src/content/docs/reference/configuration/step-execution.mdx
Outdated
Show resolved
Hide resolved
11417a0 to
7dc63bb
Compare
7dc63bb to
5e56496
Compare
pkgs/website/src/content/docs/news/pgflow-0-14-0-conditional-step-execution.mdx
Outdated
Show resolved
Hide resolved
5e56496 to
208f76f
Compare
208f76f to
b7b1a8c
Compare
963cad9 to
736e5b4
Compare
b7b1a8c to
096d008
Compare
🔍 Preview Deployment: Website✅ Deployment successful! 🔗 Preview URL: https://pr-594.pgflow.pages.dev 📝 Details:
_Last updated: _ |

Add Conditional Steps and Error Handling
This PR introduces comprehensive support for conditional step execution and graceful error handling in pgflow. The new features allow workflows to adapt to runtime conditions and handle failures without stopping the entire run.
Key Features
if/ifNotconditions using PostgreSQL's JSON containment operatorfail,skip, orskip-cascadeoptionsretriesExhausted: 'skip'for non-critical stepsVisual Representation
Added a new
step_skippedstyle to the D2 theme for visualizing skipped steps in flow diagrams.Documentation
Added comprehensive documentation with:
These features enable more resilient workflows where non-critical steps can fail without stopping the entire process.