Wrapping combinators (TaskSeq.map, taskSeq { for .. }) yield the final item twice over an external IAsyncEnumerable on a non-default TaskScheduler (Orleans grain)
Mantenedores costumam responder em até 3 dias
Um pull request relacionado já foi integrado.
- #458 de @github-actions — integrado
Avaliação
- Dificuldade
- 4/5
- Tempo estimado
- 3-5 dias
- Facilidade para iniciantes
- 45/100
- Tipo de issue
- Bug
- Clareza
- Razoavelmente clara
- Status de atividade
- Ativa
- Stack de tecnologia
- fsharp
- Domínio
- backend
Direção de pesquisa
Comece por tests/Orleans.FSharp.Integration/FunctionalPhaseFIntegrationTests.fs por volta das linhas 598-627 e FunctionalPhaseFFixture.fs por volta das linhas 305-324; em seguida, execute o comando dotnet test filtrado fornecido. Compare a enumeração direta com os caminhos dos wrappers TaskSeq.map e taskSeq no scheduler do Orleans. A tarefa estará concluída quando os caminhos encapsulados não produzirem mais o item final duas vezes e a enumeração direta continuar correta.
Escrita pelo modelo de indexação a partir do texto da issue.
Descrição
Summary
TaskSeq.map and taskSeq { for item in upstream do yield ... } over an externally produced IAsyncEnumerable<T> each yield the final item twice when the consumption runs on a non-default TaskScheduler — observed deterministically inside a Microsoft Orleans grain activation (Orleans' per-activation scheduler). Enumerating the same IAsyncEnumerable<T> directly (the exact await foreach desugaring: GetAsyncEnumerator / MoveNextAsync / Current / DisposeAsync) yields the correct count.
Environment
FSharp.Control.TaskSeq0.6.0- .NET 10 (
net10.0), F# - Reproduces identically on Microsoft Orleans 10.1.0 and 10.2.2 (the enumerable being wrapped is produced by Orleans'
IAsyncEnumerableGrainExtensionmachinery — batchedMoveNextpulls over grain calls)
The discriminator (what isolates it to the wrapping construct)
One grain method consumes the same 3-item upstream stream three ways and returns the three counts as an ordinary unary reply, so nothing about our own streaming-reply transport participates in the measurement:
let! direct = TaskSeq.toListAsync (upstream.watch (label, 3)) // plain enumeration of the source
let! viaMap =
upstream.watch (label2, 3)
|> TaskSeq.map (fun tick -> tick.note) // wrapped
|> TaskSeq.toListAsync
let! viaFor =
TaskSeq.toListAsync (taskSeq { // wrapped
for tick in upstream.watch (label3, 3) do yield tick.note
})
Result, measured 2026-08-18, stable across runs and across both Orleans versions:
(List.length direct, List.length viaMap, List.length viaFor) = (3, 4, 4)
direct = 3 is correct; both wrapping forms report 4 items for a 3-item stream, the last item duplicated.
What tracing showed
Instrumenting all enumerator layers on the failing path localized it precisely: the taskSeq wrapper yielded one extra MoveNextAsync = true with a stale Current immediately after the inner enumerator had already answered false.
What we ruled out
- Our own enumerable implementation:
directenumeration is correct everywhere, including batched sources, empty sources, and a throwing producer. - The obvious structural suspects: four progressively more faithful offline models on the ordinary thread pool — an all-synchronous enumerator, a batched one, one whose terminating
MoveNextAsynccompletes asynchronously, and a full in-process re-implementation of the Orleans pull loop driving two stacked legs — none reproduced it. The trigger appears to require the customTaskScheduleran Orleans activation runs on.
Repro status (honest)
We could not reduce it to a standalone console repro — that is the main obstacle to a better report, and why this issue points at a live test instead. In our repository it reproduces deterministically:
- The discriminator test (asserts
direct = 3; deliberately does not pin the divergent value so an upstream fix cannot break our suite): https://github.com/Neftedollar/orleans-fsharp/blob/e31b2e3c5190acb1cbcaadd4078dccd8d67b6b95/tests/Orleans.FSharp.Integration/FunctionalPhaseFIntegrationTests.fs#L598-L627 - The in-grain probe that performs the three consumptions: https://github.com/Neftedollar/orleans-fsharp/blob/e31b2e3c5190acb1cbcaadd4078dccd8d67b6b95/tests/Orleans.FSharp.Integration/FunctionalPhaseFFixture.fs#L305-L324
To observe the raw counts: clone the branch, change the discriminator's assertion to print the tuple, and run dotnet test tests/Orleans.FSharp.Integration --filter "FullyQualifiedName~consuming an upstream stream inside a grain".
Happy to run any diagnostic build or instrumented package against this environment if that helps narrow it down.
- Linguagem predominante
- F#
- Estrelas
- 111
- Forks
- 13
- Merge médio
- 2d 2h
- PRs com merge (30d)
- 1
Preparar o ambiente
- Sem Dockerfile nem arquivo Docker Compose
- Sem modelo de pull request
- Ler o guia de contribuição
Primeiros passos
- Leia a issue inteira e depois o guia de contribuição do projeto.
- Comente na issue dizendo que vai assumir — evita que duas pessoas façam o mesmo trabalho.
- Faça um fork do repositório e trabalhe em uma branch.
- Abra um pull request que referencie o número da issue.
Mais de fsprojects/FSharp.Control.TaskSeq
-
agentic-workflows automation repo-assist
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 70/100
fsprojects/FSharp.Control.TaskSeq#463 ·
Mantenedores costumam responder em até 3 dias
-
agentic-workflows automation repo-assist
Dificuldade 1/5 1-3 horas Facilidade para iniciantes 35/100
fsprojects/FSharp.Control.TaskSeq#476 · 1 comentário ·
Mantenedores costumam responder em até 3 dias
-
bug
Dificuldade 4/5 3-5 dias Facilidade para iniciantes 45/100
fsprojects/FSharp.Control.TaskSeq#473 · 2 comentários · 1 reação ·
Mantenedores costumam responder em até 3 dias
-
automation enhancement repo-assist
Dificuldade 5/5 Mais de uma semana Facilidade para iniciantes 10/100
fsprojects/FSharp.Control.TaskSeq#471 ·
Mantenedores costumam responder em até 3 dias
-
enhancement needs triage
Dificuldade 5/5 Mais de uma semana Facilidade para iniciantes 45/100
fsprojects/FSharp.Control.TaskSeq#466 · 1 comentário ·
Mantenedores costumam responder em até 3 dias
Todas as issues de fsprojects/FSharp.Control.TaskSeq
Issues semelhantes
-
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 70/100
Uuriko/project-room#3728 ·
Mantenedores costumam responder em até 1 dia
-
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 72/100
Koenkk/zigbee2mqtt#33402 ·
Mantenedores costumam responder em até 1 dia
-
routedockHono mpp-charge and session handlers rethrow every error, bypassing the logger and returning Hono's plain-text 500Talvez já em andamento @EmmanuelAjogu assumiu hoje. AbertaP2 provider sdk Stellar Wave Wave 10
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 72/100
winsznx/routedock#559 · 2 comentários ·
Mantenedores costumam responder em até 1 dia
-
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 78/100
adcontextprotocol/adcp-go#567 ·
Mantenedores costumam responder em até 1 dia
-
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 66/100
Mantenedores costumam responder em até 1 dia