Skip to content

void/db can't start on the D1 primary or carry a bookmark across requests #755

Closed

Description

@karthickeyan-dev

Version

void 1.7.0

Problem

Follow-up to #337, which asked for read replication and per-request sessions.

During a request, db from void/db always starts with withSession('first-unconstrained'), and each request gets a new session. That covers read-your-writes within one request, but not across requests: a write followed by a read in the next request can reach a replica that hasn't caught up.

The D1 guide says to handle this like so:

If another read must start with the latest primary data, use env.DB.withSession('first-primary') from cloudflare:workers.

That's the raw D1 API, and there's no supported way to run Drizzle queries on it:

  • createDb() calls withSession('first-unconstrained') itself, so it can't be given a different constraint.
  • createPrimaryDb() exists in src/runtime/db.ts, but it's private and only used outside a request.
  • Using drizzle() directly needs drizzle-orm as a dependency, and void/db is meant to replace that.

So a read that must be fresh has to become raw SQL with hand-written row types.

This affects common flows:

  • A form saves and redirects, and the next page's loader shows the old data.
  • A user pays and is sent to a page gated on that payment, and a replica says they haven't paid.
  • A webhook looks up a row created by an earlier request and doesn't find it.

Proposal

  1. A way to get a Drizzle db that starts on the primary and keeps the app's schema, such as createDb(env.DB, { session: 'first-primary' }) or an exported primaryDb.
  2. An opt-in bookmark that carries across requests: Void saves getBookmark() in a cookie when a request ends and starts the next request's session from it, so a user always sees their own writes.

Either one would solve the gated-page case. The first suits individual reads and also covers webhooks, which have no cookie. The second fixes the redirect-after-write case across a whole app.

Prior art

Rails' DatabaseSelector and Laravel's sticky option both send a user's reads to the primary after they write.

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

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Fields

Priority

None yet

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions