Skip to Content
BridgesRuntime

Bridge Runtime

Understanding how Orderly executes bridges helps you write more reliable integrations.

Execution Flow

When a bridge task is triggered (by schedule, API call, or webhook):

  1. Load — The bridge module is loaded and its manifest is validated
  2. Initializebridge.initialize(config) is called with the bridge’s stored credentials
  3. Executebridge.executeTask(taskName, context, input) runs the task
  4. Record — The result is saved to task_executions with status, metrics, and timing
  5. Cleanupbridge.destroy() is called if implemented

Task Queuing

Tasks are queued via Upstash QStash for reliable async execution:

  • Tasks are deduplicated by bridge + task name
  • Failed tasks are retried with exponential backoff
  • Execution timeout is 5 minutes per task
  • Concurrent tasks per bridge are limited to prevent rate limiting

Error Handling

When a task fails, return error details in the result:

return { success: false, error: { code: 'API_ERROR', message: 'Platform returned 429 Too Many Requests', retryable: true, details: { statusCode: 429, retryAfter: 60 }, }, };

Error Codes

Use meaningful error codes:

CodeWhen to Use
AUTH_ERRORInvalid credentials or expired token
API_ERRORPlatform API returned an error
RATE_LIMITEDToo many requests
NOT_FOUNDRequested resource doesn’t exist
VALIDATION_ERRORInvalid input data
TIMEOUTRequest timed out
UNKNOWN_TASKTask name not recognized

Retryable Errors

Set retryable: true for transient errors (rate limits, timeouts, 5xx responses). Orderly will automatically retry the task with backoff.

Set retryable: false for permanent errors (invalid credentials, missing resources). These won’t be retried.

Logging

Use the provided logger in the task context:

context.logger.info('Fetching orders', { page: 1, limit: 100 }); context.logger.warn('Rate limited, backing off', { retryAfter: 60 }); context.logger.error('API call failed', error, { endpoint: '/orders' });

Logs are associated with the task execution and viewable in the portal.

Storage

Use context.storage for persistent data between executions:

// Store a cursor with 24-hour TTL await context.storage.set('lastCursor', cursor, 86400); // Retrieve it next time const lastCursor = await context.storage.get<string>('lastCursor');

Storage is scoped to the bridge instance — different instances of the same bridge type have separate storage.