> For the complete documentation index, see [llms.txt](https://brightercommand.gitbook.io/paramore-brighter-documentation/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://brightercommand.gitbook.io/paramore-brighter-documentation/commands-handlers-and-pipelines/buildingapipeline/policyretryandcircuitbreaker.md).

# Supporting Retry and Circuit Breaker

Brighter is a Command Processor and supports a pipeline of Handlers to handle orthogonal requests.

> **How-to** · Applies to **Brighter V10**

Brighter is a [Command Processor](https://www.goparamore.io/control-bus-and-data-bus/) and supports a [pipeline of Handlers to handle orthogonal requests](/paramore-brighter-documentation/commands-handlers-and-pipelines/buildingapipeline.md).

Amongst the valuable uses of orthogonal requests is patterns to support Quality of Service in a distributed environment: [Timeout, Retry, and Circuit Breaker](#using-brighters-useresiliencepipeline-attribute).

Even if you don't believe that you are writing a distributed system that needs this protection, consider that as soon as you have multiple processes, such as a database server, you are distributed.

Brighter uses [Polly](https://github.com/App-vNext/Polly) to support Retry and Circuit-Breaker. Through our [Russian Doll Model](/paramore-brighter-documentation/commands-handlers-and-pipelines/buildingapipeline.md) we are able to run the target handler in the context of a Policy Handler, that catches exceptions, and applies a Policy on how to deal with them.

## Polly v8 Resilience Pipelines

**Brighter supports** [**Polly v8**](https://www.pollydocs.org/) **Resilience Pipelines**, which provides a modern, streamlined API for building resilience strategies:

* **Full Polly v8 Support**: Access to all Polly v8 resilience strategies (Retry, Circuit Breaker, Timeout, Rate Limiter, Fallback, Hedging)
* **New `UseResiliencePipeline` Attribute**: Replaces `UsePolicy` attribute for Polly v8 pipelines
* **Enhanced Context Integration**: Request context integrates with Polly's resilience context
* **Proper CancellationToken Flow**: Cancellation tokens flow correctly through resilience pipelines
* **Type-Scoped Pipelines**: Support for per-handler-type pipelines (useful for Circuit Breakers)

### Migration from V9 to V10

| V9 (Polly v7)                                | V10 (Polly v8)                                        | Notes                                               |
| -------------------------------------------- | ----------------------------------------------------- | --------------------------------------------------- |
| `[UsePolicy]`                                | `[UseResiliencePipeline]`                             | New attribute for Polly v8 pipelines                |
| `[TimeoutPolicy]`                            | `[UseResiliencePipeline]` with Timeout strategy       | **TimeoutPolicy deprecated in V10, removed in V11** |
| `PolicyRegistry`                             | `ResiliencePipelineRegistry<string>`                  | From Polly.Registry namespace                       |
| Policies configured with `Policy.Handle<>()` | Pipelines configured with `ResiliencePipelineBuilder` | New fluent API                                      |

> **⚠️ DEPRECATION NOTICE**: The `TimeoutPolicyAttribute` is marked as obsolete in V10 and will be removed in V11. Migrate to `UseResiliencePipeline` with a Timeout strategy instead.

***

## Using Brighter's UseResiliencePipeline Attribute

By adding the **UseResiliencePipeline** attribute, you instruct the Command Processor to insert a handler (filter) into the pipeline that runs all later steps using that Polly resilience pipeline.

### Basic Example

```csharp
using Paramore.Brighter;
using Paramore.Brighter.Policies.Attributes;

public class MyQoSProtectedHandler : RequestHandler<MyCommand>
{
    [UseResiliencePipeline(policy: "MyRetryPipeline", step: 1)]
    public override MyCommand Handle(MyCommand command)
    {
        // Do work that could throw errors due to distributed computing reliability
        return base.Handle(command);
    }
}
```

### Async Handlers Take UseResiliencePipelineAsync

`UseResiliencePipeline` decorates a synchronous `Handle`. An async handler takes the async attribute instead, and pairing them the other way round leaves the pipeline out of the chain:

```csharp
using System.Threading;
using System.Threading.Tasks;
using Paramore.Brighter;
using Paramore.Brighter.Policies.Attributes;

public class MyQoSProtectedHandlerAsync : RequestHandlerAsync<MyCommand>
{
    [UseResiliencePipelineAsync(policy: "MyRetryPipeline", step: 1)]
    public override async Task<MyCommand> HandleAsync(
        MyCommand command, CancellationToken cancellationToken = default)
    {
        // Do work that could throw errors due to distributed computing reliability
        return await base.HandleAsync(command, cancellationToken);
    }
}
```

Both attributes read from the same `ResiliencePipelineRegistry<string>`, so a pipeline name registered once serves handlers of either kind.

### Configuring Resilience Pipelines

To configure a Polly resilience pipeline, you use the `ResiliencePipelineRegistry<string>` to register pipelines with a name. At runtime, Brighter looks up that pipeline by name.

#### Retry Strategy Example

```csharp
using System;
using Polly;
using Polly.Registry;
using Polly.Retry;

var resiliencePipelineRegistry = new ResiliencePipelineRegistry<string>();

resiliencePipelineRegistry.TryAddBuilder("MyRetryPipeline",
    (builder, context) => builder.AddRetry(new RetryStrategyOptions
    {
        MaxRetryAttempts = 3,
        Delay = TimeSpan.FromSeconds(1),
        BackoffType = DelayBackoffType.Exponential,
        OnRetry = args =>
        {
            // Log retry attempt
            Console.WriteLine($"Retry {args.AttemptNumber} after {args.RetryDelay}");
            return default;
        }
    }));
```

#### Circuit Breaker Strategy Example

```csharp
using System;
using Polly;
using Polly.CircuitBreaker;

resiliencePipelineRegistry.TryAddBuilder("MyCircuitBreakerPipeline",
    (builder, context) => builder.AddCircuitBreaker(new CircuitBreakerStrategyOptions
    {
        FailureRatio = 0.5,              // Break if 50% of requests fail
        MinimumThroughput = 10,          // Need at least 10 requests before breaking
        SamplingDuration = TimeSpan.FromSeconds(30),
        BreakDuration = TimeSpan.FromSeconds(60),
        OnOpened = args =>
        {
            // Log circuit breaker opened
            Console.WriteLine($"Circuit breaker opened after {args.BreakDuration}");
            return default;
        },
        OnClosed = args =>
        {
            // Log circuit breaker closed
            Console.WriteLine("Circuit breaker closed");
            return default;
        }
    }));
```

#### Timeout Strategy Example

**V10**: Use Polly's Timeout strategy instead of the deprecated `TimeoutPolicyAttribute`:

```csharp
using System;
using Polly;

resiliencePipelineRegistry.TryAddBuilder("MyTimeoutPipeline",
    (builder, context) => builder.AddTimeout(TimeSpan.FromSeconds(5)));
```

**Handler Usage**:

```csharp
using Paramore.Brighter;
using Paramore.Brighter.Policies.Attributes;

public class MyTimedHandler : RequestHandler<MyCommand>
{
    // V9 (deprecated):
    // [TimeoutPolicy(milliseconds: 5000, step: 1)]

    // V10 (recommended):
    [UseResiliencePipeline(policy: "MyTimeoutPipeline", step: 1)]
    public override MyCommand Handle(MyCommand command)
    {
        // Work that should timeout after 5 seconds
        return base.Handle(command);
    }
}
```

***

## Combining Multiple Strategies

You can combine multiple resilience strategies in a single pipeline. The first strategy you add is the outermost: it wraps every strategy added after it. So to time out each attempt, retry the attempts that fail, and stop retrying while a service is known to be down, add the circuit breaker first and the timeout last.

### Retry + Circuit Breaker + Timeout

```csharp
using System;
using Polly;
using Polly.CircuitBreaker;
using Polly.Retry;

resiliencePipelineRegistry.TryAddBuilder("MyComprehensivePipeline",
    (builder, context) => builder
        .AddCircuitBreaker(new CircuitBreakerStrategyOptions
        {
            FailureRatio = 0.5,
            MinimumThroughput = 10,
            BreakDuration = TimeSpan.FromSeconds(60)
        })                                                  // Outermost: Circuit breaker
        .AddRetry(new RetryStrategyOptions
        {
            MaxRetryAttempts = 3,
            Delay = TimeSpan.FromSeconds(1),
            BackoffType = DelayBackoffType.Exponential
        })                                                  // Middle: Retry on failures
        .AddTimeout(TimeSpan.FromSeconds(10)));             // Innermost: Timeout individual attempts
```

Added the other way round, the timeout would wrap the retries and limit all of them together to 10 seconds, and the circuit breaker would sit inside the retry.

**Handler Usage**:

```csharp
using Paramore.Brighter;
using Paramore.Brighter.Policies.Attributes;

public class MyQoSProtectedHandler : RequestHandler<MyCommand>
{
    [UseResiliencePipeline("MyComprehensivePipeline", step: 1)]
    public override MyCommand Handle(MyCommand command)
    {
        // Protected by timeout, retry, and circuit breaker
        return base.Handle(command);
    }
}
```

**How it works**:

1. Circuit breaker checks if circuit is open (fails fast if open)
2. Retry wraps the operation (retries on failures)
3. Timeout wraps each individual attempt (times out after 10 seconds per attempt)

> **Note**: If retries are exhausted, the exception will bubble out to the Circuit Breaker, which will count it as a failure.

***

## Combining Resilience Strategies on a Handler

A handler method takes one `[UseResiliencePipeline]`. The attribute is not repeatable, so a second one on the same method does not compile (`CS0579`, *"Duplicate 'UseResiliencePipeline' attribute"*). To layer strategies, compose them in one pipeline, as [Combining Multiple Strategies](#combining-multiple-strategies) shows, and name that:

```csharp
using System;
using Paramore.Brighter;
using Paramore.Brighter.Policies.Attributes;
using Polly;
using Polly.CircuitBreaker;
using Polly.Registry;
using Polly.Retry;

resiliencePipelineRegistry.TryAddBuilder("MyCircuitBreakerAndRetryPipeline",
    (builder, context) => builder
        .AddCircuitBreaker(new CircuitBreakerStrategyOptions())  // Outermost
        .AddRetry(new RetryStrategyOptions()));                   // Inside the circuit breaker

public class MyMultiPipelineHandler : RequestHandler<MyCommand>
{
    [UseResiliencePipeline("MyCircuitBreakerAndRetryPipeline", step: 1)]
    public override MyCommand Handle(MyCommand command)
    {
        // Circuit breaker wraps retry, which wraps this handler
        return base.Handle(command);
    }
}
```

Other attributes, such as `[FallbackPolicy]` or `[RejectMessageOnError]`, can still sit beside it at their own steps.

***

## Type-Scoped Pipelines

For strategies like Circuit Breaker, you often want a separate instance for each kind of request, so that failures handling one don't trip the breaker for the others. Set `UseTypePipeline = true` and Brighter looks up a pipeline typed for the handler's request, a `ResiliencePipeline<TRequest>`, under the policy name.

```csharp
using Paramore.Brighter;
using Paramore.Brighter.Policies.Attributes;

public class OrderServiceHandler : RequestHandler<ProcessOrderCommand>
{
    [UseResiliencePipeline("SharedCircuitBreaker", step: 1, UseTypePipeline = true)]
    public override ProcessOrderCommand Handle(ProcessOrderCommand command)
    {
        // Uses the circuit breaker typed for ProcessOrderCommand
        return base.Handle(command);
    }
}

public class PaymentServiceHandler : RequestHandler<ProcessPaymentCommand>
{
    [UseResiliencePipeline("SharedCircuitBreaker", step: 1, UseTypePipeline = true)]
    public override ProcessPaymentCommand Handle(ProcessPaymentCommand command)
    {
        // Uses the circuit breaker typed for ProcessPaymentCommand, separate from ProcessOrderCommand's
        return base.Handle(command);
    }
}
```

**How it works**: When `UseTypePipeline = true`, Brighter calls `GetPipeline<TRequest>(policy)` on the registry. The key is the policy name alone, and the pipeline must be registered typed for the request. Polly keeps typed pipelines apart by their type, so `ProcessOrderCommand` and `ProcessPaymentCommand` each get their own instance under the same name; two handlers of the same request share one. The attribute's XML documentation describes a key built from the handler's type name, but Brighter V10 does not look one up, and a pipeline registered under such a key is never found.

**Configuration**:

```csharp
using Polly;
using Polly.CircuitBreaker;

// Register a pipeline typed for each request, under the policy name
resiliencePipelineRegistry.TryAddBuilder<ProcessOrderCommand>("SharedCircuitBreaker",
    (builder, context) => builder.AddCircuitBreaker(new CircuitBreakerStrategyOptions<ProcessOrderCommand>()));

resiliencePipelineRegistry.TryAddBuilder<ProcessPaymentCommand>("SharedCircuitBreaker",
    (builder, context) => builder.AddCircuitBreaker(new CircuitBreakerStrategyOptions<ProcessPaymentCommand>()));
```

***

## All Available Polly v8 Strategies

Polly v8 provides the following resilience strategies, all of which can be used with Brighter:

| Strategy            | Description                                         | Use Case                                                 |
| ------------------- | --------------------------------------------------- | -------------------------------------------------------- |
| **Retry**           | Retries operations that fail transiently            | Network glitches, temporary service unavailability       |
| **Circuit Breaker** | Prevents cascading failures by breaking the circuit | Dependency is down, prevent overwhelming failed services |
| **Timeout**         | Limits operation execution time                     | Prevent hanging on slow operations                       |
| **Rate Limiter**    | Controls the rate of operations                     | Throttle requests to external APIs                       |
| **Fallback**        | Provides alternative value/action on failure        | Graceful degradation, cached responses                   |
| **Hedging**         | Executes parallel operations and takes first result | Improve latency in distributed systems                   |

### Rate Limiter Example

The rate limiter strategies ship in their own package, `Polly.RateLimiting`, which Brighter does not reference. Add it to your project before you use them:

```bash
dotnet add package Polly.RateLimiting
```

```csharp
using System.Threading.RateLimiting;
using Polly;

resiliencePipelineRegistry.TryAddBuilder("MyRateLimiterPipeline",
    (builder, context) => builder.AddConcurrencyLimiter(new ConcurrencyLimiterOptions
    {
        PermitLimit = 10,  // Maximum 10 concurrent requests
        QueueLimit = 20    // Queue up to 20 additional requests
    }));
```

### Hedging Example

Hedging produces a result, so it lives in a pipeline typed for that result, as a Polly fallback does. `[UseResiliencePipeline]` cannot attach it to a handler; resolve it with `GetPipeline<HttpResponseMessage>("MyHedgingPipeline")` and run your call through it inside the handler.

```csharp
using System;
using System.Net.Http;
using Polly;
using Polly.Hedging;

resiliencePipelineRegistry.TryAddBuilder<HttpResponseMessage>("MyHedgingPipeline",
    (builder, context) => builder.AddHedging(new HedgingStrategyOptions<HttpResponseMessage>
    {
        MaxHedgedAttempts = 3,
        Delay = TimeSpan.FromMilliseconds(500),
        ActionGenerator = args =>
        {
            // Generate hedged action (e.g., call different endpoint)
            return () => CallAlternativeEndpoint();
        }
    }));
```

***

## CancellationToken Integration

Polly v8 resilience pipelines properly integrate with `CancellationToken`, allowing you to cancel operations in progress.

```csharp
using System.Threading;
using System.Threading.Tasks;
using Paramore.Brighter;
using Paramore.Brighter.Policies.Attributes;

public class MyCancellableHandler : RequestHandlerAsync<MyCommand>
{
    [UseResiliencePipelineAsync("MyRetryPipeline", step: 1)]
    public override async Task<MyCommand> HandleAsync(
        MyCommand command,
        CancellationToken cancellationToken = default)
    {
        // CancellationToken flows through the resilience pipeline
        await SomeAsyncOperation(cancellationToken);
        return command;
    }
}
```

***

## Request Context Integration

The request context carries a Polly `ResilienceContext`. When you set `RequestContext.ResilienceContext` before you send, Brighter runs the handler's resilience pipeline with that context, so a callback such as `OnRetry` can read the properties you put in it. Brighter adds no properties of its own.

```csharp
using Paramore.Brighter;
using Polly;
using Polly.Retry;

var tenantKey = new ResiliencePropertyKey<string>("tenant-id");

resiliencePipelineRegistry.TryAddBuilder("MyContextAwarePipeline",
    (builder, context) => builder.AddRetry(new RetryStrategyOptions
    {
        MaxRetryAttempts = 3,
        OnRetry = args =>
        {
            // Read what the caller put into Polly's resilience context
            if (args.Context.Properties.TryGetValue(tenantKey, out var tenantId))
            {
                // Use the value for logging, tracing, etc.
            }
            return default;
        }
    }));

// When you send, attach the resilience context to the request context
var resilienceContext = ResilienceContextPool.Shared.Get();
resilienceContext.Properties.Set(tenantKey, "tenant-42");

commandProcessor.Send(new MyCommand(), new RequestContext { ResilienceContext = resilienceContext });

ResilienceContextPool.Shared.Return(resilienceContext);
```

See [Request Context documentation](/paramore-brighter-documentation/commands-handlers-and-pipelines/buildingapipeline/usingthecontextbag.md) for more details on accessing the resilience context from handlers.

***

## Registering Pipelines with CommandProcessor

When creating your `CommandProcessor`, pass the `ResiliencePipelineRegistry<string>` to `Resilience`:

```csharp
using Paramore.Brighter;
using Paramore.Brighter.Extensions;
using Polly;
using Polly.Registry;
using Polly.Retry;

// Start from Brighter's own pipelines. AddBrighterDefault uses TryAddBuilder, so it
// backfills the pipelines Brighter requires without replacing any you have registered.
var resiliencePipelineRegistry = new ResiliencePipelineRegistry<string>()
    .AddBrighterDefault();

// Configure your own pipelines (see examples above)
resiliencePipelineRegistry.TryAddBuilder("MyRetryPipeline",
    (builder, _) => builder.AddRetry(new RetryStrategyOptions()));

var commandProcessor = CommandProcessorBuilder.StartNew()
    .Handlers(new HandlerConfiguration(
        subscriberRegistry: registry,
        handlerFactory: handlerFactory))
    .Resilience(resiliencePipelineRegistry, policyRegistry)  // policyRegistry is optional
    .NoExternalBus()
    .NoInstrumentation()
    .RequestContextFactory(new InMemoryRequestContextFactory())
    .RequestSchedulerFactory(new InMemorySchedulerFactory())
    .Build();
```

`Resilience` takes the Polly v8 registry first and an optional Polly v7 `IPolicyRegistry<string>` second — **one call, not two.** If you have no legacy policies to carry, call `DefaultResilience()` instead and Brighter supplies its own registry.

> **Call `AddBrighterDefault` whenever you build the registry yourself.** Brighter requires a pipeline registered under `CommandProcessor.OutboxProducer`, and `Resilience` throws `ConfigurationException` on its first statement when the registry does not have one — at **startup**, before any message is sent. Brighter only fills the gap for you when you supply *no* registry at all, because the container does it with `??=`.

Or using dependency injection with ASP.NET Core, registering the `MyQoSProtectedHandler` from the first example:

```csharp
using Microsoft.Extensions.DependencyInjection;
using Paramore.Brighter;
using Paramore.Brighter.Extensions;
using Paramore.Brighter.Extensions.DependencyInjection;
using Polly;
using Polly.CircuitBreaker;
using Polly.Registry;
using Polly.Retry;

var resiliencePipelineRegistry = new ResiliencePipelineRegistry<string>()
    .AddBrighterDefault();

resiliencePipelineRegistry.TryAddBuilder("MyRetryPipeline",
    (builder, _) => builder.AddRetry(new RetryStrategyOptions()));

resiliencePipelineRegistry.TryAddBuilder("MyCircuitBreakerPipeline",
    (builder, _) => builder.AddCircuitBreaker(new CircuitBreakerStrategyOptions()));

services.AddBrighter(options =>
{
    options.HandlerLifetime = ServiceLifetime.Scoped;
    options.ResiliencePipelineRegistry = resiliencePipelineRegistry;
})
.Handlers(registry =>
{
    registry.Register<MyCommand, MyQoSProtectedHandler>();
});
```

**There is no fluent `ConfigureResiliencePipelines` method on the DI builder.** The registry is a settable property on `BrighterOptions`, set inside the `AddBrighter` options delegate as above. This is the same `??=` case as the builder: assigning your own registry means Brighter never calls `AddBrighterDefault` for you, so call it yourself.

***

## Retry and Circuit Breaker Best Practices

1. **Use Resilience Pipelines for New Code**: Prefer `UseResiliencePipeline` over legacy `UsePolicy` for new handlers.
2. **Migrate Away from TimeoutPolicy**: Replace `[TimeoutPolicy]` with `[UseResiliencePipeline]` using Polly's Timeout strategy. TimeoutPolicy will be removed in V11.
3. **Use Type-Scoped Pipelines for Circuit Breakers**: Set `UseTypePipeline = true` when using Circuit Breakers to avoid failures in one handler affecting others.
4. **Combine Strategies Thoughtfully**: When combining timeout, retry, and circuit breaker:
   * Put timeout innermost (times out individual attempts)
   * Put retry in the middle (retries failed attempts)
   * Put circuit breaker outermost (prevents retry when service is known to be down)
5. **Configure Appropriate Delays**: Use exponential backoff for retries to avoid overwhelming recovering services.
6. **Monitor Circuit Breaker State**: Use `OnOpened`, `OnClosed`, and `OnHalfOpened` callbacks to log and monitor circuit breaker state changes.
7. **Pass CancellationTokens**: Always pass and respect `CancellationToken` in async handlers to support cancellation through resilience pipelines.
8. **Use Request Context**: Leverage request context integration for correlation IDs, tracing, and logging within resilience callbacks.

***

## Retry and Circuit Breaker Troubleshooting

### Pipeline Not Found Exception

**Symptom**: `ConfigurationException: Error when building pipeline`, thrown by `Send` before the handler runs. Its inner `KeyNotFoundException` reads *Unable to find a resilience pipeline associated with the key 'MyPipeline'*.

**Solution**: Ensure you've registered the pipeline with the exact name referenced in the attribute:

```csharp
using Polly;
using Polly.Retry;

resiliencePipelineRegistry.TryAddBuilder("MyPipeline",
    (builder, context) => builder.AddRetry(new RetryStrategyOptions()));
```

### Type Pipeline Not Found Exception

**Symptom**: the same `ConfigurationException`, whose inner `KeyNotFoundException` reads *Unable to find a generic resilience pipeline of 'MyCommand' associated with the key 'MyPipeline'*.

**Solution**: When using `UseTypePipeline = true`, register the pipeline typed for the handler's request, under the policy name:

```csharp
using Polly;
using Polly.Retry;

resiliencePipelineRegistry.TryAddBuilder<MyCommand>("MyPipeline",
    (builder, context) => builder.AddRetry(new RetryStrategyOptions<MyCommand>()));
```

### TimeoutPolicy Obsolete Warning

**Symptom**: Compiler warning: `'TimeoutPolicyAttribute' is obsolete: 'It is recommended to use UsePolicyAttribute or UseResiliencePipelineAttribute instead'`

**Solution**: Replace `[TimeoutPolicy]` with `[UseResiliencePipeline]` using Polly's Timeout strategy (see [Migrating to Polly v8](/paramore-brighter-documentation/commands-handlers-and-pipelines/buildingapipeline/policyretryandcircuitbreaker/migratingtopollyv8.md)).

***

## Further Reading

* [Migrating to Polly v8](/paramore-brighter-documentation/commands-handlers-and-pipelines/buildingapipeline/policyretryandcircuitbreaker/migratingtopollyv8.md) - The V9 to V10 migration steps, and the deprecated Polly v7 attribute
* [Polly v8 Documentation](https://www.pollydocs.org/)
* [Polly v7 to v8 Migration Guide](https://www.pollydocs.org/migration-v8.html)
* [Brighter Fallback Policy](/paramore-brighter-documentation/commands-handlers-and-pipelines/buildingapipeline/policyfallback.md)
* [Brighter Request Context](/paramore-brighter-documentation/commands-handlers-and-pipelines/buildingapipeline/usingthecontextbag.md)
* [Building a Handler Pipeline](/paramore-brighter-documentation/commands-handlers-and-pipelines/buildingapipeline.md)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://brightercommand.gitbook.io/paramore-brighter-documentation/commands-handlers-and-pipelines/buildingapipeline/policyretryandcircuitbreaker.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
