Angular: whenStable() resolves while a mutation started with mutate() is still running
メンテナーはふだん 1 日以内に返信
評価
- 難易度
- 3/5
- 見積もり時間
- 1〜2日
- 初心者へのやさしさ
- 30/100
- issue の種類
- バグ
- 明瞭さ
- 明確に書かれている
- 活発さ
- 停滞
- 技術スタック
- angular, typescript
調査の方向性
packages/angular-query-experimental/src/inject-mutation.ts#L135-L146 の保留中タスクの登録から始め、packages/angular-query-experimental/src/tests/pending-tasks.test.ts のリグレッションケースを実行してください。mutation.mutate() の後に ApplicationRef.whenStable() がミューテーションの完了まで待機し、任意のタイムアウトなしでステータスとデータのアサーションが成功することを確認してください。
索引モデルが issue の本文から書いたものです。
説明
Describe the bug
ApplicationRef.whenStable() resolves while a mutation started with mutate() is still running, so tests and SSR see the mutation as untouched.
injectMutation registers the Angular pending task from inside the observer subscription callback:
That callback is wrapped in notifyManager.batchCalls, so it runs in a later task than the mutate() call that started the mutation. In the window between the two there is no pending task, the application counts as stable, and whenStable() resolves right away. At that point the result signals have not been updated either, so status() still reads idle.
mutate() is fire and forget, so there is nothing else holding the application busy. mutateAsync() is not affected in the same way because the caller gets a promise back and can await it.
Your minimal, reproducible example
Failing test against main, added to packages/angular-query-experimental/src/__tests__/pending-tasks.test.ts:
it('should let whenStable wait for a mutation that was just triggered', async () => {
vi.useRealTimers()
const app = TestBed.inject(ApplicationRef)
const mutation = TestBed.runInInjectionContext(() =>
injectMutation(() => ({
mutationFn: (value: string) => sleep(5).then(() => value),
})),
)
TestBed.tick()
mutation.mutate('mutated')
await app.whenStable()
expect(mutation.status()).toBe('success')
expect(mutation.data()).toBe('mutated')
})
On current main this fails with expected 'idle' to be 'success'.
Steps to reproduce
- Set up a zoneless
TestBedwithprovideTanStackQuery. - Create a mutation with
injectMutationwhosemutationFntakes any real time. - Call
mutation.mutate(...). await ApplicationRef.whenStable().- Read
mutation.status().
Expected behavior
whenStable() should not resolve until the mutation has settled, the same way it already waits for queries once they have been reported. Right now the only way to make it wait is to insert an arbitrary setTimeout before calling it.
How often does this bug happen?
Every time
Screenshots or Videos
No response
Platform
Reproduced with the repository test suite on Windows 11, Node 24.
Tanstack Query adapter
angular-query
TanStack Query version
5.101.4 (current main)
TypeScript version
5.9.3
Additional context
The same batching gap exists on the query side and is reported in #9981, #9910 and #10046. This issue is only about the mutation path, which those reports do not cover. I have a fix and a regression test ready and will open a PR.
- 主要言語
- TypeScript
- スター
- 50.4k
- フォーク
- 4.2k
- 平均マージ
- 11時間 33分
- マージ済み PR(30日)
- 421
環境構築
- Dockerfile・Docker Compose ファイルなし
- プルリクエストのテンプレートあり
- コントリビューションガイドを読む
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
TanStack/query のほかの issue
-
solid-query: STRICT_READ_UNTRACKED on Solid 2 — client()/options() read in component body (useMutation, useBaseQuery)再び着手できるかも このイシューのプルリクエストはマージされずにクローズされました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 84/100
TanStack/query#11358 · コメント 2 件 · リアクション 1 件 ·
メンテナーはふだん 1 日以内に返信
-
solid-query: switching the queryClient accessor strands the new client's cache (subscription stays on the old observer)対応中かも @MaNaN1803 が 74 日前に担当しました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 84/100
TanStack/query#11106 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
難易度 4/5 3〜5日 初心者へのやさしさ 45/100
メンテナーはふだん 1 日以内に返信
-
setQueryData: NoInfer loses discriminated-union members when spreading a narrowed updater value対応中かも @iosayin が今日担当しました。 オープン
難易度 4/5 3〜5日 初心者へのやさしさ 55/100
メンテナーはふだん 1 日以内に返信
-
setQueryData updater loses discriminated-union fields when spreading inferred NoInfer data対応中かも @boriskozak が今日担当しました。 オープン
難易度 4/5 3〜5日 初心者へのやさしさ 68/100
TanStack/query#11794 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
似ている issue
-
bug
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
AOSSIE-Org/DebateAI#611 ·
メンテナーはふだん 3 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 65/100
openzim/mwoffliner#2933 ·
メンテナーはふだん 1 日以内に返信
-
Use the README category name for website links and submissions対応中かも @dajiaohuang が今日担当しました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
birobirobiro/awesome-shadcn-ui#647 ·
メンテナーはふだん 2 日以内に返信
-
Twake Drive picker: closePicker() never destroys the intent (stop() is on the promise returned by start(), not by create())対応中かも @chibenwa が今日担当しました。 オープンclaude
難易度 2/5 1〜3時間 初心者へのやさしさ 84/100
linagora/twake-calendar-frontend#1498 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
check:passed streams:add
難易度 2/5 1〜3時間 初心者へのやさしさ 68/100
メンテナーはふだん 1 日以内に返信