microsoft / microsoft/aspire

Should Aspire integrations ship Roslyn analyzers for service-side deprecations? (e.g., RabbitMQ transient_nonexcl_queues)

Open
#17,149 1 comment 0 reactions 0 assignees View on GitHub
area-integrations triage:bot-seen
Dominant language
C#
Stars
6.3k
Forks
991
Avg merge
2d 15h
Merged PRs (30d)
196

Description

# Should Aspire integrations ship analyzers for service-side deprecations?

## Background

Aspire integrations default to a specific container/service version (e.g., `Aspire.Hosting.RabbitMQ` currently pins `rabbitmq:4.3`). When the underlying service deprecates or removes a capability that customers can still call via the underlying client library, customers learn about it at runtime — usually through a hard-to-diagnose protocol error.

**Concrete motivating example.** RabbitMQ 4.3 disables the deprecated `transient_nonexcl_queues` feature by default. Calls like:

```csharp
await channel.QueueDeclareAsync(queueName, durable: false, exclusive: false);
```

are now rejected with AMQP error 541 (`INTERNAL_ERROR - Feature 'transient_nonexcl_queues' is deprecated.`). This affected our own test fixtures and would equally affect any customer app that pinned this pattern. Fix in PR #17148: bump the image and switch the affected test queue declarations to `exclusive: true`.

`QueueDeclare*` is owned by the upstream `RabbitMQ.Client` NuGet, not by Aspire, so we cannot mark it `[Obsolete]` from our side. The natural upstream solution would be for `RabbitMQ.Client` itself to add an analyzer or `[Obsolete]` overload, but that may not happen or may lag behind the broker's deprecation timeline.

## Question

Should Aspire integrations ship Roslyn analyzers that flag patterns deprecated by the service version we default to? For example:

- `Aspire.RabbitMQ.Client` ships a `RabbitMQDeprecatedPatternsAnalyzer` that flags `QueueDeclare*` calls with `durable: false, exclusive: false` and `x-queue-mode` / `x-queue-version=1` queue arguments (CQv1, also removed in 4.3).
- `Aspire.MongoDB.Driver`, `Aspire.Confluent.Kafka`, `Aspire.Npgsql`, etc. could grow analogous rules over time for their respective services.

## Tradeoffs

**Pros**

- Catches at compile time instead of runtime — much better DX than diagnosing an AMQP 541 or equivalent.
- Aligns the integration's static guidance with the container/broker's actual runtime behavior.
- Aspire already has the infrastructure (`src/Aspire.Hosting.Analyzers`, `src/Aspire.Hosting.Integration.Analyzers`) and ships analyzers with packages, so this isn't a new build/packaging problem.
- Helps customers prepare for upgrades before they happen.

**Cons**

- **Limited reach.** Static analysis only catches literal/default values. Customers who pass `durable: config["..."]` won't be flagged. Many real-world callers fall into this category.
- **Two API shapes per ecosystem are common.** RabbitMQ alone has v6 (sync) and v7+ (async) with different overload sets and parameter orders. Other ecosystems have similar bifurcations.
- **Ownership editorialization.** We'd be adding warnings on top of a third-party library's API surface. Not unprecedented (EF Core, ASP.NET Core ship analyzers for their own APIs), but it'd be the first time Aspire does it for a transitive third-party API.
- **Slippery slope / commitment.** RabbitMQ 4.3 also removed `x-queue-mode` and `x-queue-version=1`. Future RabbitMQ versions will deprecate more. Each integration has its own analogous list. Are we committing to keep these analyzers current across every integration?
- **False positives for opted-in users.** A customer with `deprecated_features.permit.transient_nonexcl_queues = true` in their `rabbitmq.conf` is making a deliberate choice. Analyzer noise would frustrate them unless we expose a suppression path.

## Possible outcomes

1. **Don't do this.** Rely on upstream libraries and runtime errors, document deprecations in our README/conceptual docs (this is the path taken by PR #17148 for the immediate RabbitMQ case).
2. **Do it case-by-case** when the deprecation is sufficiently high-impact and the upstream library has not (and is unlikely to) addressed it. Start with RabbitMQ 4.3 deprecations as a proof-of-concept.
3. **Do it systematically** as a standing pattern for every integration, with shared infrastructure and a policy that says when an analyzer is warranted.

I lean toward option 1 or 2 for now; opening this issue so the broader team can weigh in.

## Related

- PR #17148 — RabbitMQ 4.3 bump and test fixes that motivated this question.
- [RabbitMQ 4.3.0 release notes](https://github.com/rabbitmq/rabbitmq-server/releases/tag/v4.3.0) — listing the deprecated features now disabled by default.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.