MCPcopy Create free account
hub / github.com/TanStack/db / cleanupQueryIfIdle

Function cleanupQueryIfIdle

packages/query-db-collection/src/query.ts:1556–1623  ·  view source on GitHub ↗
(hashedQueryKey: string)

Source from the content-addressed store, hash-verified

1554 * Respects refcounts and invalidateQueries cycles via hasListeners().
1555 */
1556 const cleanupQueryIfIdle = (hashedQueryKey: string) => {
1557 const refcount = queryRefCounts.get(hashedQueryKey) || 0
1558 const observer = state.observers.get(hashedQueryKey)
1559 const effectivePersistedGcTime =
1560 effectivePersistedGcTimes.get(hashedQueryKey)
1561
1562 if (refcount <= 0) {
1563 // Drop our subscription so hasListeners reflects only active consumers
1564 unsubscribes.get(hashedQueryKey)?.()
1565 unsubscribes.delete(hashedQueryKey)
1566 }
1567
1568 const hasListeners = observer?.hasListeners() ?? false
1569
1570 if (hasListeners) {
1571 // During invalidateQueries, TanStack Query keeps internal listeners alive.
1572 // Leave refcount at 0 but keep observer so it can resubscribe.
1573 queryRefCounts.set(hashedQueryKey, 0)
1574 return
1575 }
1576
1577 // No listeners means the query is truly idle.
1578 // Even if refcount > 0, we treat hasListeners as authoritative to prevent leaks.
1579 // This can happen if subscriptions are GC'd without calling unloadSubset.
1580 if (refcount > 0) {
1581 console.warn(
1582 `[cleanupQueryIfIdle] Invariant violation: refcount=${refcount} but no listeners. Cleaning up to prevent leak.`,
1583 { hashedQueryKey },
1584 )
1585 }
1586
1587 if (
1588 effectivePersistedGcTime !== undefined &&
1589 metadata &&
1590 persistedMetadata?.row.scanPersisted
1591 ) {
1592 begin()
1593 metadata.collection.set(
1594 `${QUERY_COLLECTION_GC_PREFIX}${hashedQueryKey}`,
1595 {
1596 queryHash: hashedQueryKey,
1597 mode:
1598 effectivePersistedGcTime === Number.POSITIVE_INFINITY
1599 ? `until-revalidated`
1600 : `ttl`,
1601 ...(effectivePersistedGcTime === Number.POSITIVE_INFINITY
1602 ? {}
1603 : { expiresAt: Date.now() + effectivePersistedGcTime }),
1604 },
1605 )
1606 commit()
1607 if (effectivePersistedGcTime !== Number.POSITIVE_INFINITY) {
1608 schedulePersistedRetentionExpiry({
1609 queryHash: hashedQueryKey,
1610 mode: `ttl`,
1611 expiresAt: Date.now() + effectivePersistedGcTime,
1612 })
1613 }

Callers 2

internalSyncFunction · 0.85
unloadSubsetFunction · 0.85

Calls 5

cleanupQueryInternalFunction · 0.85
getMethod · 0.45
deleteMethod · 0.45
setMethod · 0.45

Tested by

no test coverage detected