Skip to content

[RFC] Add retryable_exceptions filter to retry policies #454

@vasudev13

Description

@vasudev13

Motivation

Both built-in policies retry on any exception. This means a ValueError from a malformed response or a KeyError in parsing logic burns through all attempts even though retrying will never help — only transient failures like network timeouts or rate limits warrant a retry.

Proposed Change

Add an optional retryable_exceptions parameter to both concrete policy classes. Default None preserves existing behavior, no breaking changes.

Since workflows-py is LLM-agnostic, the parameter accepts any exception type(s) the caller needs. Example -

OpenAI

from openai import RateLimitError, APITimeoutError, APIConnectionError

@step(retry_policy=ExponentialBackoffRetryPolicy(
    maximum_attempts=5,
    retryable_exceptions=(RateLimitError, APITimeoutError, APIConnectionError),
))
async def call_openai(self, ev: QueryEvent) -> ResultEvent: ...

Anthropic

from anthropic import RateLimitError, APIConnectionError

@step(retry_policy=ConstantDelayRetryPolicy(
    delay=10,
    maximum_attempts=3,
    retryable_exceptions=(RateLimitError, APIConnectionError),
))
async def call_anthropic(self, ev: QueryEvent) -> ResultEvent: ...

Gemini

from google.api_core.exceptions import ResourceExhausted, ServiceUnavailable

@step(retry_policy=ExponentialBackoffRetryPolicy(
    maximum_attempts=5,
    retryable_exceptions=(ResourceExhausted, ServiceUnavailable),
))
async def call_gemini(self, ev: QueryEvent) -> ResultEvent: ...

Implementation is ~3 lines per policy — early-return None if not isinstance(error, self.retryable_exceptions).

Questions

  1. Is this in scope for the built-in policies, or is the intent that users subclass RetryPolicy for this level of control?
  2. Happy to open a PR if the direction looks good — I contributed the ExponentialBackoffRetryPolicy previously so I know this surface area well.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions