Skip to content

Commit

Permalink
Add RunnableRetry Documentation (#13074)
Browse files Browse the repository at this point in the history
  • Loading branch information
eyurtsev authored Nov 8, 2023
1 parent 55aeff6 commit 06c503f
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 1 deletion.
11 changes: 11 additions & 0 deletions libs/langchain/langchain/schema/runnable/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -644,6 +644,17 @@ def with_retry(
wait_exponential_jitter: bool = True,
stop_after_attempt: int = 3,
) -> Runnable[Input, Output]:
"""Create a new Runnable that retries the original runnable on exceptions.
Args:
retry_if_exception_type: A tuple of exception types to retry on
wait_exponential_jitter: Whether to add jitter to the wait time
between retries
stop_after_attempt: The maximum number of attempts to make before giving up
Returns:
A new Runnable that retries the original runnable on exceptions.
"""
from langchain.schema.runnable.retry import RunnableRetry

return RunnableRetry(
Expand Down
73 changes: 72 additions & 1 deletion libs/langchain/langchain/schema/runnable/retry.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,84 @@


class RunnableRetry(RunnableBinding[Input, Output]):
"""Retry a Runnable if it fails."""
"""Retry a Runnable if it fails.
A RunnableRetry helps can be used to add retry logic to any object
that subclasses the base Runnable.
Such retries are especially useful for network calls that may fail
due to transient errors.
The RunnableRetry is implemented as a RunnableBinding. The easiest
way to use it is through the `.with_retry()` method on all Runnables.
Example:
Here's an example that uses a RunnableLambda to raise an exception
.. code-block:: python
import time
def foo(input) -> None:
'''Fake function that raises an exception.'''
raise ValueError("Invoking foo failed. At time {time.time()}")
runnable = RunnableLambda(foo)
runnable_with_retries = runnable.with_retry(
retry_exception_types=(ValueError,), # Retry only on ValueError
wait_exponential_jitter=True, # Add jitter to the exponential backoff
max_attempt_number=2, # Try twice
)
# The method invocation above is equivalent to the longer form below:
runnable_with_retries = RunnableRetry(
bound=runnable,
retry_exception_types=(ValueError,),
max_attempt_number=2,
wait_exponential_jitter=True
)
This logic can be used to retry any Runnable, including a chain of Runnables,
but in general it's best practice to keep the scope of the retry as small as
possible. For example, if you have a chain of Runnables, you should only retry
the Runnable that is likely to fail, not the entire chain.
Example:
.. code-block:: python
from langchain.chat_models import ChatOpenAI
from langchain.prompts import PromptTemplate
template = PromptTemplate.from_template("tell me a joke about {topic}.")
model = ChatOpenAI(temperature=0.5)
# Good
chain = template | model.with_retry()
# Bad
chain = template | model
retryable_chain = chain.with_retry()
"""

retry_exception_types: Tuple[Type[BaseException], ...] = (Exception,)
"""The exception types to retry on. By default all exceptions are retried.
In general you should only retry on exceptions that are likely to be
transient, such as network errors.
Good exceptions to retry are all server errors (5xx) and selected client
errors (4xx) such as 429 Too Many Requests.
"""

wait_exponential_jitter: bool = True
"""Whether to add jitter to the exponential backoff."""

max_attempt_number: int = 3
"""The maximum number of attempts to retry the runnable."""

@property
def _kwargs_retrying(self) -> Dict[str, Any]:
Expand Down

0 comments on commit 06c503f

Please sign in to comment.