# Endpoint Configuration Foundation

## Goal

Configure receive endpoints intentionally so naming, concurrency, retry, and topology behavior stay predictable across environments.

## Agent enforcement rules

### Do

- Select endpoint naming conventions intentionally for the environment.
- Prefer consumer definitions for retry/outbox/endpoint settings.
- Tune `PrefetchCount` and `ConcurrentMessageLimit` based on downstream capacity.

### Do not

- Do not mix manual endpoint configuration and `ConfigureEndpoints` without intentional ordering.
- Do not increase concurrency without validating downstream stability.
- Do not introduce a service-wide formatter or prefix without coordinating it with the services that share the broker.


## Build checklist

- Use `ConfigureEndpoints(context)` for convention-based endpoint setup.
- Use the default endpoint formatter unless a service-wide naming format or environment prefix is needed.
- Use consumer definitions for retry, outbox, and endpoint behavior.
- Configure manual `ReceiveEndpoint(...)` only when you need precise queue-level control.
- Set `PrefetchCount` and endpoint `ConcurrentMessageLimit` deliberately for throughput and stability. A consumer definition's `ConcurrentMessageLimit` limits that consumer, not every consumer on a shared endpoint.

## Example: convention-based endpoints with custom prefix to separate environments on brokers like SQS that are shared

```csharp
services.AddMassTransit(x =>
{
    x.AddConsumer<SubmitOrderConsumer>();
    
    x.SetEndpointNameFormatter(new KebabCaseEndpointNameFormatter(prefix: "dev"));

    x.UsingRabbitMq((context, cfg) =>
    {
        cfg.ConfigureEndpoints(context);
    });
});
```

## Example: manual endpoint with explicit limits

```csharp
services.AddMassTransit(x =>
{
    x.AddConsumer<SubmitOrderConsumer>();

    x.UsingRabbitMq((context, cfg) =>
    {
        cfg.PrefetchCount = 32;

        cfg.ReceiveEndpoint("order-service", e =>
        {
            e.ConcurrentMessageLimit = 28;
            e.ConfigureConsumer<SubmitOrderConsumer>(context);
        });
    });
});
```

## Example: consumer definition pipeline settings

```csharp
public class SubmitOrderConsumerDefinition : ConsumerDefinition<SubmitOrderConsumer>
{
    public SubmitOrderConsumerDefinition()
    {
        EndpointName = "order-service";
        ConcurrentMessageLimit = 8;
    }

    protected override void ConfigureConsumer(
        IReceiveEndpointConfigurator endpointConfigurator,
        IConsumerConfigurator<SubmitOrderConsumer> consumerConfigurator,
        IRegistrationContext context)
    {
        endpointConfigurator.UseMessageRetry(r => r.Intervals(100, 200, 500, 800, 1000));
        endpointConfigurator.UseInMemoryOutbox(context);
    }
}
```

## Guardrails

- Do not mix manual endpoint configuration and `ConfigureEndpoints` without clear ordering.
- Do not change endpoint naming without considering existing queues and collaborating services.
- Do not tune concurrency without validating downstream dependencies.

## Verification

- `dotnet build`
- `dotnet test --filter Consumer`
- `dotnet test --filter Endpoint`

## References

- [Consumers (Concepts)](/concepts/consumers)
- [Configuration Overview](/configuration)
- [Consumer Configuration](/configuration/consumers)
- [Topology Configuration](/configuration/topology)
