CleanupQueue schedules GC deadlines on wall-clock time but services them with an elapsed-time timer
メンテナーはふだん 1 日以内に返信
まだ誰も着手していません。
評価
- 難易度
- 3/5
- 見積もり時間
- 1〜2日
- 初心者へのやさしさ
- 78/100
- issue の種類
- バグ
- 明瞭さ
- 明確に書かれている
- 活発さ
- 活発
- 技術スタック
- typescript
- 領域
- performance
調査の方向性
packages/db/src/collection/cleanup-queue.ts から始めて、schedule、updateTimeout、process を追跡します。提供された決定論的な例でクロックのステップ変化のシナリオを再現し、その後、期限とタイマー処理が同じ経過時間用のクロックを使用していることを確認します。Date.now() が後戻りしても gcTime の後にクリーンアップが実行され、関連する Vitest の動作が成功すれば完了です。
索引モデルが issue の本文から書いたものです。
説明
CleanupQueue schedules GC deadlines on wall-clock time but services them with an elapsed-time timer
Package: @tanstack/db 0.8.7 — packages/db/src/collection/cleanup-queue.ts (unchanged on main at the time of writing).
What happens
CleanupQueue.schedule records executeAt = Date.now() + gcTime. updateTimeout arms setTimeout(process, executeAt - Date.now()), and process runs a task only when Date.now() >= task.executeAt, otherwise re-arming for the remainder.
setTimeout measures elapsed time; Date.now() is the realtime clock. When realtime moves backwards between schedule and process — an NTP step, a VM or container guest resynchronising with its host, a manual clock change — process finds now < executeAt and re-arms for executeAt - now, which is roughly the size of the step. Every pending cleanup is delayed by that amount regardless of its gcTime.
For a live query collection this delays the release of its subscriptions to its source collections: a component unmounts, the live query's gcTime (1 ms under @tanstack/react-db's useLiveQuery) elapses, and the source still counts it as a subscriber seconds later.
How it was observed
In a Vitest lane that waits for source collections to reach zero subscribers before disposing them, the wait timed out intermittently with the queue holding one task whose executeAt was 1.7–2.7 s ahead of Date.now() and its timer armed for that difference. A sampler on the same machine (a WSL2 guest with an in-guest time-sync service) recorded the realtime clock stepping back ~3.7 s periodically while performance.now() advanced steadily. The environment is only how it was noticed; any realtime step reproduces it.
Deterministic reproduction
import { createCollection, createLiveQueryCollection } from '@tanstack/db'
const source = createCollection<{ id: string }>({
id: 'source',
getKey: (row) => row.id,
startSync: true,
sync: { sync: ({ markReady }) => { markReady(); return () => {} } },
})
const live = createLiveQueryCollection({
query: (q) => q.from({ s: source }),
gcTime: 1,
startSync: true,
})
const subscription = live.subscribeChanges(() => {})
console.log(source.subscriberCount) // 1
subscription.unsubscribe() // live query's GC is scheduled: executeAt = Date.now() + 1
const realNow = Date.now
Date.now = () => realNow() - 3000 // realtime steps back 3 s before the timer fires
setTimeout(() => console.log(source.subscriberCount), 100) // still 1
setTimeout(() => console.log(source.subscriberCount), 3500) // 0 — released ~3 s late
With a monotonic deadline the second log would already read 0 at 100 ms.
Suggested property
Deadlines and the timer that services them should share a clock: compute executeAt from a monotonic elapsed-time source (for example performance.now(), with Date.now() only as a fallback where it is unavailable) so that a realtime step cannot move a scheduled cleanup. The specific implementation is up to you; the property is that process runs a task once the elapsed time since schedule reaches gcTime.
- 主要言語
- TypeScript
- スター
- 3.9k
- フォーク
- 272
- 平均マージ
- 1日 1時間
- マージ済み PR(30日)
- 210
環境構築
- Dockerfile・Docker Compose ファイルなし
- プルリクエストのテンプレートあり
- コントリビューションガイドを読む
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
TanStack/db のほかの issue
-
難易度 5/5 1週間以上 初心者へのやさしさ 5/100
メンテナーはふだん 1 日以内に返信
-
browser-db-sqlite-persistence: option to load the wa-sqlite WASM by URL instead of inlined base64オープン
難易度 4/5 3〜5日 初心者へのやさしさ 35/100
メンテナーはふだん 1 日以内に返信
-
難易度 4/5 3〜5日 初心者へのやさしさ 45/100
メンテナーはふだん 1 日以内に返信
-
難易度 3/5 1〜2日 初心者へのやさしさ 72/100
メンテナーはふだん 1 日以内に返信
-
electric-db-collection: on-demand + persistence fails after relaunch with "Snapshot requests are not supported in full mode"対応中かも @KyleAMathews が 3 日前に担当しました。 オープン
難易度 3/5 1〜2日 初心者へのやさしさ 68/100
TanStack/db#2056 · リアクション 1 件 ·
メンテナーはふだん 1 日以内に返信
似ている issue
-
Table: Space fires onActivate in single-selection mode — the reference doc and the JSDoc disagreeオープン
難易度 2/5 1〜3時間 初心者へのやさしさ 68/100
sidorares/react-x11-components#764 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 76/100
backnotprop/plannotator#1840 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
JoviDeCroock/pracht#432 ·
メンテナーはふだん 1 日以内に返信
-
approved check:passed streams:add
難易度 1/5 1時間未満 初心者へのやさしさ 75/100
メンテナーはふだん 1 日以内に返信
-
Hardware attribute name "app Connection Support" has inconsistent casing対応中かも このイシューにリンクされたプルリクエストがオープン中、またはマージ済みです。 オープン
難易度 1/5 1時間未満 初心者へのやさしさ 88/100
walletbeat/walletbeat#1628 ·
メンテナーはふだん 1 日以内に返信