microsoft / microsoft/aspire

Cosmos DB emulator: gateway HTTP/2 client leaves unobserved read-loop task exceptions on cancelled reads — default the emulator client to HTTP/1.1

Open
#18,541 2 comments 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

### Is there an existing issue for this?

- [x] I have searched the existing issues (related: #5364 emulator hangs via connection string, #9326 emulator not creating dbs/containers)

### Describe the bug

When connecting to the Cosmos DB emulator (`RunAsEmulator`) in gateway mode, the `CosmosClient` negotiates **HTTP/2** via ALPN. On a cold or slow emulator, reads that hit the request timeout are cancelled mid-flight, and the underlying HTTP/2 read-loop task is left **unobserved**. It surfaces later as a `TaskScheduler.UnobservedTaskException` / finalizer `AggregateException` (HTTP/2 stream aborted), which is noisy and, depending on `ThrowUnobservedTaskExceptions`, can destabilize the host.

The real Cosmos service is fine over HTTP/2; this is specific to the **emulator's** gateway endpoint, especially during the cold-start window.

### Expected behavior

When `RunAsEmulator` is used, the Aspire-provided Cosmos connection/client defaults (and the `AddAzureCosmosClient` wiring) should pin the emulator's `HttpClient` to **HTTP/1.1** gateway mode so cancelled reads cannot leave an orphaned HTTP/2 read loop — or document/expose this so consumers don't have to hand-configure it.

### Steps to reproduce

1. `AddAzureCosmosDB("cosmos").RunAsEmulator()`.
2. A service that reads a container shortly after startup, while the emulator is still warming.
3. Observe `UnobservedTaskException` / finalizer `AggregateException` for an aborted HTTP/2 read when a read is cancelled by the request timeout.

### Workaround (for reference)

We configure the emulator `CosmosClient`'s `HttpClient` for HTTP/1.1 only and raise the request timeout, on the emulator branch only:

```csharp
new CosmosClientOptions
{
HttpClientFactory = () =>
{
var handler = new SocketsHttpHandler();
var http = new HttpClient(handler)
{
DefaultRequestVersion = HttpVersion.Version11,
DefaultVersionPolicy = HttpVersionPolicy.RequestVersionExact,
};
return http;
},
RequestTimeout = TimeSpan.FromSeconds(30), // emulator only; default 5s too tight on cold start
// ... emulator endpoint / connection mode
};
```

Pinning HTTP/1.1 kills the ALPN HTTP/2 read loop entirely, so a cancelled read can't leave an unobserved task. The timeout bump separately reduces cold-start cancellations.

### Environment

- Aspire 13.4.x
- Cosmos DB emulator (vnext-latest / preview), gateway mode, run mode (local dev)

Contributor guide

Open the contributing guide

Research direction

Start at the AddAzureCosmosClient wiring and the RunAsEmulator branch, then inspect how the emulator CosmosClientOptions and HttpClient are constructed. Reproduce a cold-start read timeout and verify that emulator clients use HTTP/1.1 and no unobserved read-loop exceptions occur after cancellation.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp
Domain
databases
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.