Error Boundaries ๐Ÿ›ก๏ธ

Keep your workflows resilient with error boundaries - they're like try-catch blocks for your workflow! Protect nodes, handle failures gracefully, and keep your workflow running smoothly.

Why Use Error Boundaries? ๐Ÿค”

Error boundaries are your workflow's safety net! They help you:

  • ๐Ÿ›ก๏ธ Protect critical nodes from failures
  • ๐Ÿงน Run cleanup operations when things go wrong
  • ๐Ÿ”„ Implement recovery strategies
  • ๐Ÿ“Š Track and handle errors elegantly
  • ๐Ÿš€ Keep parts of your workflow running even when some nodes fail

Basic Usage โœจ

Wrap your nodes in an error boundary to handle failures gracefully:

import { GraphCompose } from '@graph-compose/client';

const workflow = new GraphCompose()
  // Add payment node
  .node('payment')
    .post('https://api.example.com/payment')
  .end()
  
  // Add error boundary
  .errorBoundary('payment_error_handler', ['payment'])
    .post('https://api.example.com/payment-cleanup')
  .end();

Example Error Boundary Request Body

If the payment node fails, the request sent to https://api.example.com/payment-cleanup would look like this (assuming no other body fields were defined for the error boundary itself):

{
  "errorContext": {
    "message": "Payment processing failed due to insufficient funds", // Example error message
    "failedNodeId": "payment",
    "timestamp": 1710000000000 // Example timestamp
  }
}

If you defined a body in your error boundary configuration, the errorContext would be merged into it:

SDK with Body

// ... inside workflow definition
.errorBoundary('payment_error_handler', ['payment'])
  .post('https://api.example.com/payment-cleanup')
  .withBody({ 
    transactionId: "{{ results.some_previous_node.transactionId }}", // Data from other nodes
    reason: "Cleanup requested"
  })
.end();

Resulting Request Body

{
  "transactionId": "txn_12345", // Resolved from results.some_previous_node
  "reason": "Cleanup requested",
  "errorContext": {
    "message": "Payment processing failed...",
    "failedNodeId": "payment",
    "timestamp": 1710000000000
  }
}

Multiple Boundaries ๐ŸŽฏ

You can have multiple boundaries protecting different parts of your workflow. We'll always execute the most specific (closest) error boundary - just like how try-catch blocks work!

import { GraphCompose } from '@graph-compose/client';

const workflow = new GraphCompose()
  // Add workflow nodes
  .node('fetch_user')
    .get('https://api.example.com/user')
  .end()
  
  .node('fetch_orders')
    .withDependencies(['fetch_user'])
    .get('https://api.example.com/orders')
  .end()
  
  .node('process_orders')
    .withDependencies(['fetch_orders'])
    .post('https://api.example.com/process')
  .end()
  
  // Add specific error handler
  .errorBoundary('specific_error_handler', ['fetch_orders'])
    .post('https://api.example.com/order-error')
  .end()
  
  // Add general error handler
  .errorBoundary('general_error_handler', ['fetch_user', 'fetch_orders', 'process_orders'])
    .post('https://api.example.com/general-error')
  .end();

How Specificity Works ๐ŸŽฏ

When an error occurs, we find the most specific error boundary:

  1. First, we look for boundaries that directly protect the failed node
  2. If multiple boundaries protect the node, we use the one that protects the fewest nodes (most specific)
  3. Only one error boundary will execute - the most specific one
  4. Other error boundaries are ignored, just like how only one catch block handles an error

Common Use Cases ๐ŸŽฏ

๐Ÿ”„

Transaction Rollback

Roll back partial transactions when operations fail, such as releasing inventory holds when payments fail.

๐Ÿ“Š

Notification & Logging

Send alerts and log detailed error information when critical operations fail.

๐Ÿ”„

Fallback Logic

Implement fallback mechanisms like trying backup services or providing degraded service.

Cleanup Operations ๐Ÿงน

import { GraphCompose } from '@graph-compose/client';

const workflow = new GraphCompose()
  .node('create_resources')
    .post('https://api.example.com/resources')
  .end()
  
  .errorBoundary('cleanup_handler', ['create_resources'])
    .post('https://api.example.com/cleanup')
  .end();

Retry Logic ๐Ÿ”„

import { GraphCompose } from '@graph-compose/client';

const workflow = new GraphCompose()
  .node('process_data')
    .post('https://api.example.com/process')
  .end()
  
  .errorBoundary('retry_handler', ['process_data'])
    .post('https://api.example.com/retry')
  .end();

Best Practices ๐Ÿ’ก

Make your error boundaries work for you:

  • ๐ŸŽฏ Protect critical operations
  • ๐Ÿ” Log error details for debugging
  • ๐Ÿงน Always clean up resources on failure
  • ๐Ÿ“Š Track error patterns
  • ๐Ÿš€ Implement smart recovery strategies
  • โšก Use specific error boundaries for specific failure modes
  • ๐Ÿ›ก๏ธ Layer error boundaries for different levels of protection

Ready to make your workflows more resilient? Let's go! ๐Ÿš€