Skip to content

Collection.cleanup() resolves before asynchronous source cleanup finishes #1891

Description

@cucumber-sp

Version

@tanstack/db@0.9.2 (also visible in current main).

Collection.cleanup() is declared async and its doc comment says to wait until cleanup completes before starting a new sync session. But the sync CleanupFn is typed () => void, and CollectionImpl.cleanup() calls the synchronous lifecycle cleanup then returns Promise.resolve(); it does not wait for a Promise returned by a source cleanup callback.

Minimal runtime reproduction:

import { createCollection } from '@tanstack/db'

const gate = Promise.withResolvers<void>()
const collection = createCollection({
  id: 'cleanup-repro',
  getKey: (row: { id: string }) => row.id,
  sync: {
    sync: ({ markReady }) => {
      markReady()
      return { cleanup: () => gate.promise }
    },
  },
})

await collection.preload()
let sourceCleanupDone = false
gate.promise.then(() => { sourceCleanupDone = true })
await collection.cleanup()
console.log(sourceCleanupDone) // false

Returning a Promise from a void callback type is accepted by TypeScript, but it is silently ignored. The same issue affects adapters that initiate asynchronous teardown/durable work from a synchronous cleanup callback.

Impact: An app that awaits collection.cleanup() before constructing a replacement collection over the same SQLite database can still have old-session cleanup in flight. That work may reach the replacement session or persist row deletes after new-session hydration. We currently need a separate application-level drain/cancel barrier before same-user replacement.

Expected: Either support CleanupFn: () => void | Promise<void> and make await collection.cleanup() wait for source cleanup, or explicitly document that cleanup only initiates teardown and provide an awaitable settlement hook/barrier. The current async return shape and comment suggest a stronger guarantee than the implementation gives.

This is separate from #1889: that issue is a late startup callback invoking markReady after cleanup; this issue is the absence of an awaitable source-cleanup completion contract.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions