Skip to content

Conversation

@joaodaher
Copy link
Contributor

@joaodaher joaodaher commented Sep 26, 2025

Adds try/catch blocks and retry policies to enhance workflow resilience. This change introduces:

  • Try/catch blocks for error handling, enabling workflows to gracefully manage exceptions and execute fallback logic.
  • Retry policies for workflow steps, allowing automatic retries with configurable backoff strategies.

This enhancement improves the robustness and reliability of workflows by providing mechanisms to recover from transient failures and handle errors in a controlled manner.


Note

Introduce try/catch error handling and retry policies with full YAML/codegen support, new example workflows, and comprehensive tests/docs; bump version to 0.0.2.

  • Core:
    • Add TryCatchStep, TryCatchBuilder, and try_catch API (core/error_handling.py); export via core/__init__.py and package __init__.py.
  • Codegen:
    • Emit retry config (predicate/backoff) and timeout per step; generate try/except blocks for TryCatchStep.
    • Refactor workflow emission to process nested steps; preserve required headers and run-id capture.
  • Examples:
    • Add examples/app/flows/resilient_payment.py and data_pipeline.py; update examples/app/main.py imports.
  • Tests:
    • Add unit tests for Arg, RetryPolicy, step core/execution, workflow core, and try/catch.
    • Add codegen tests + fixtures for retry and try/catch (tests/codegen/...); update smoke runner script references.
  • Docs:
    • Update README.md to mark Retries/Try-catch as supported and add roadmap; tweak CONTRIBUTING.md and smoke instructions; add .cursor/rules/writing-tests.mdc.
  • Version:
    • Bump package to 0.0.2.

Written by Cursor Bugbot for commit df49371. This will update automatically on new commits. Configure here.

- add comprehensive tests for workflow registry and builder
- test step execution paths and non-callable steps
- cover ArgExpr coercion and expression chaining
- test runtime router building with mixed step types
- validate all error conditions and edge cases

brings core modules from 88% to 99% coverage
- implement RetryPolicy with configurable backoff
- add retry YAML emission in codegen
- support retries for both Python steps and HttpSteps
- include example payment workflow with retry logic
- add comprehensive tests and snapshots

allows steps to automatically retry on transient failures
Copilot AI review requested due to automatic review settings September 26, 2025 16:30
@qltysh
Copy link

qltysh bot commented Sep 26, 2025

All good ✅

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR introduces try/catch blocks and retry policies to enhance workflow resilience. The implementation adds comprehensive error handling mechanisms that allow workflows to gracefully handle exceptions and recover from transient failures through configurable retry strategies.

  • Adds TryCatchStep and TryCatchBuilder for structured exception handling with fallback logic
  • Implements RetryPolicy with configurable backoff strategies for automatic retries on failures
  • Provides YAML code generation support for both try/catch blocks and retry configurations

Reviewed Changes

Copilot reviewed 24 out of 24 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/fastapi_cloudflow/core/error_handling.py New module defining TryCatchStep and TryCatchBuilder classes for workflow exception handling
src/fastapi_cloudflow/codegen/workflows.py Updates YAML generation to support try/catch blocks and retry policy emission
src/fastapi_cloudflow/init.py Exports new try/catch functionality and helper functions
tests/unit/test_try_catch.py Comprehensive unit tests for try/catch functionality
tests/unit/test_retry_policy.py Unit tests for retry policy features
tests/codegen/test_try_catch_codegen.py Tests for try/catch YAML code generation
tests/codegen/test_retry_codegen.py Tests for retry policy YAML code generation
examples/app/flows/resilient_payment.py Example workflow demonstrating retry and try/catch usage
examples/app/flows/data_pipeline.py Complex data pipeline example with nested try/catch blocks

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

if node.raise_on_error:
# Add a step to re-raise the error after handling
except_steps.append({"reraise_error": {"raise": f"${{{node.error_var}}}"}})
try_catch_def["except"]["steps"] = except_steps
Copy link

Copilot AI Sep 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reraise_error step is appended to the except_steps list after it has already been assigned to try_catch_def['except']['steps']. This creates a mutation after assignment issue. The reraise step should be appended before the assignment on line 163, or the assignment on line 167 should be removed since it's redundant.

Suggested change
try_catch_def["except"]["steps"] = except_steps

Copilot uses AI. Check for mistakes.
Comment on lines +158 to +160
# Manually make it async to avoid syntax issues
async_no_input = AsyncMock(side_effect=no_input_hint)
async_no_input.__name__ = "no_input_hint"
Copy link

Copilot AI Sep 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The comment mentions 'to avoid syntax issues' but this approach is overly complex and fragile. Consider using a proper async function definition or pytest.mark.asyncio instead of manually creating AsyncMock objects.

Copilot uses AI. Check for mistakes.
Comment on lines +115 to +125
output_model=PaymentResult, # Changed to match the actual output
try_steps=try_primary.nodes,
except_steps=[fallback_payment, log_failure], # Use actual step instances
error_var="payment_error",
raise_on_error=False, # Don't re-raise, we handled it
Copy link

Copilot AI Sep 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The inline comments on lines 115, 117, and 119 appear to be implementation notes rather than helpful code documentation. These should be removed or converted to proper documentation that explains the business logic.

Suggested change
output_model=PaymentResult, # Changed to match the actual output
try_steps=try_primary.nodes,
except_steps=[fallback_payment, log_failure], # Use actual step instances
error_var="payment_error",
raise_on_error=False, # Don't re-raise, we handled it
output_model=PaymentResult,
try_steps=try_primary.nodes,
except_steps=[fallback_payment, log_failure],
error_var="payment_error",
raise_on_error=False,

Copilot uses AI. Check for mistakes.
input_model=ProcessedData,
output_model=ProcessedData,
method="POST",
url="https://jsonplaceholder.typicode.com/posts", # Mock endpoint
Copy link

Copilot AI Sep 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Using a hardcoded mock endpoint URL in production code is not ideal. Consider using environment variables or configuration for external service URLs, even in examples.

Copilot uses AI. Check for mistakes.
Comment on lines +97 to +99
tc_step = (
try_catch("custom-error-var").try_block(try_block).except_block(except_block, error_var="my_error").build()
)
Copy link

Copilot AI Sep 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The line is split unnecessarily with parentheses. This could be written as a single line or use proper line continuation for better readability.

Suggested change
tc_step = (
try_catch("custom-error-var").try_block(try_block).except_block(except_block, error_var="my_error").build()
)
tc_step = try_catch("custom-error-var").try_block(try_block).except_block(except_block, error_var="my_error").build()

Copilot uses AI. Check for mistakes.
@joaodaher joaodaher force-pushed the feature/try-and-retry branch from b7fc83e to 2b9b5f3 Compare September 27, 2025 16:54
joaodaher added a commit that referenced this pull request Sep 27, 2025
feature #3 is now fully implemented with clean API
cursor[bot]

This comment was marked as outdated.

- add TryCatchStep and TryCatchBuilder for error recovery
- support nested try/catch with custom error variables
- emit proper Cloud Workflows try/except YAML syntax
- include data pipeline example with multi-stage error handling
- update README roadmap and mark features complete
- expose new components in package __init__

enables robust error handling and fallback strategies in workflows
@joaodaher joaodaher force-pushed the feature/try-and-retry branch from 2b9b5f3 to df49371 Compare September 27, 2025 21:35
@joaodaher joaodaher merged commit 8b86643 into main Sep 27, 2025
5 of 6 checks passed
@joaodaher joaodaher deleted the feature/try-and-retry branch September 27, 2025 21:36
joaodaher added a commit that referenced this pull request Sep 27, 2025
feature #3 is now fully implemented with clean API
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants