ChangeFeedProcessor: Regression in PR #5617 breaks AllVersionsAndDeletes push processor on cold start
needs-investigationcustomer-reported
## Describe the bug
`GetChangeFeedProcessorBuilderWithAllVersionsAndDeletes` fails on the first feed read after `StartAsync()` with HTTP 400:
```
BadRequest: Start from beginning is not supported with 'All Versions and Deletes' mode.
```
Affected SDK versions: `3.59.0` (stable) and `3.60.0-preview.0`. Same code on `3.57.0-preview.1` works.
## Bisect
PR #5617 / commit `4bec24059`, file `Microsoft.Azure.Cosmos/src/ChangeFeedProcessor/ChangeFeedProcessorCore.cs`, lines 62–69 of `StartAsync()`:
```csharp
if (!this.changeFeedProcessorOptions.StartFromBeginning
&& this.changeFeedProcessorOptions.StartTime == null
&& string.IsNullOrEmpty(this.changeFeedProcessorOptions.StartContinuation))
{
// StartTime is serialized as RFC1123 (seconds precision) and interpreted as exclusive.
// Back off by one second so writes occurring immediately after StartAsync are not missed.
this.changeFeedProcessorOptions.StartTime = DateTime.UtcNow.AddSeconds(-1);
}
```
The pre-flight that backfills `StartTime = DateTime.UtcNow.AddSeconds(-1)` (to mitigate the first-change skip reported in #5268) is unconditional on `ChangeFeedMode`. AVAD processors that don't pass an explicit start hint hit this path; the SDK frames the first feed read as `StartFromTime`, and the AVAD endpoint rejects any explicit `StartTime` — the server surfaces it as `Start from beginning is not supported with 'All Versions and Deletes' mode`.
## Repro
```csharp
ChangeFeedProcessor processor = container
.GetChangeFeedProcessorBuilderWithAllVersionsAndDeletes<JObject>(
processorName: "repro",
onChangesDelegate: (_, changes, ct) => Task.CompletedTask)
.WithInstanceName($"repro-{Guid.NewGuid():N}")
.WithLeaseContainer(leaseContainer)
.Build();
await processor.StartAsync();
```
Conditions:
- Monitored container has `ChangeFeedPolicy` retention enabled (or the account is on Continuous backup, which auto-manages AVAD retention).
- Lease container is empty (fresh deployment, no prior leases for this processor name).
- No `WithStartTime` / `WithStartFromBeginning` calls (AVAD builder throws on either).
The first feed read returns 400. On `3.57.0-preview.1` the same code starts cleanly from "now".
## Lease state is the same in both versions
The lease fields that drive the SDK's start-position decision are identical between the working (`3.57.0-preview.1`) and broken (`3.59.0` / `3.60.0-preview.0`) versions for a freshly bootstrapped lease:
```jsonc
{
"LeaseToken": "3",
"FeedRange": { "Range": { "min": "...", "max": "..." } },
"ContinuationToken": null,
"Mode": "Full-Fidelity Feed",
"Owner": null,
"version": 0,
"properties": {}
}
```
`Owner` later differs by run state (set after a successful acquire on `3.57.0-preview.1`; null on `3.60.0-preview.0` because the processor releases on the 400). `id`, `_etag`, `_ts`, `_rid` differ by document identity. The values that determine the start position — `ContinuationToken` and `Mode` — are the same. The regression is purely in the `StartAsync` pre-flight, not in lease bootstrap.
## Suggested fix
Gate the `StartTime` backfill on `ChangeFeedMode != AllVersionsAndDeletes`. AVAD has its own server-side semantics for null-continuation leases (anchor to "now"), and the −1s mitigation from #5268 isn't valid in that mode.
If first-change-skip is a real concern for AVAD too, it needs a different mitigation — e.g. probe the change feed for a "now" continuation before lease creation and persist it into the lease's `ContinuationToken`.
## Test gap
PR #5617 added three unit tests in `ChangeFeedProcessorCoreTests.cs` and an integration test in `DynamicTests.cs`. All cover LatestVersion only. The AVAD code path has no coverage for `StartAsync`'s start-position logic, which is why this regression shipped.
## Workaround
Pin to `Microsoft.Azure.Cosmos 3.57.0-preview.1` until the regression is fixed.
## Environment
- SDK Version: `3.59.0` (stable) and `3.60.0-preview.0` (both reproduce); `3.57.0-preview.1` is the last known good
- OS: Linux (x64), macOS (arm64)
- .NET: 8.0
- Cosmos account mode: Continuous backup (Continuous7Days), preview feature "All versions and deletes change feed mode" enabled at the account level
## Related
- #5268 — the first-change-skip issue that PR #5617 set out to fix (LatestVersion only)
- PR #5617 — the change that introduced this regression for AVAD
1 条评论