Skip to content

Defnull/electric dockerfile#8

Merged
define-null merged 3 commits intomainfrom
defnull/electric-dockerfile
Jul 14, 2022
Merged

Defnull/electric dockerfile#8
define-null merged 3 commits intomainfrom
defnull/electric-dockerfile

Conversation

@define-null
Copy link
Copy Markdown
Contributor

No description provided.

@define-null define-null force-pushed the defnull/electric-dockerfile branch 2 times, most recently from 60005cf to f2334f7 Compare July 14, 2022 14:26
@define-null define-null force-pushed the defnull/electric-dockerfile branch from f2334f7 to db92c33 Compare July 14, 2022 14:27
@define-null define-null marked this pull request as ready for review July 14, 2022 14:38
@define-null define-null merged commit 37fa31c into main Jul 14, 2022
@define-null define-null deleted the defnull/electric-dockerfile branch July 14, 2022 14:46
icehaunter pushed a commit that referenced this pull request Apr 17, 2023
KyleAMathews pushed a commit that referenced this pull request Nov 1, 2024
Port of our classical basic example but without writes
KyleAMathews added a commit that referenced this pull request Apr 10, 2026
Adds test/pbt-micro.test.ts — a dedicated PBT suite that exercises
twelve narrow invariants in the ShapeStream client. Each TARGET's
opening comment documents the invariant under test, and the PBTs
shook loose eight real bugs that are fixed in this commit:

  #1 canonicalShapeKey used URLSearchParams.set() for custom params,
     collapsing duplicate keys (e.g. ?tag=a&tag=b → ?tag=b) so two
     genuinely distinct shapes shared a cache key. Switched to append().

  #2 Shape#process clobbered shouldNotify by assignment in three
     places, so any sequence where a change message followed a
     status-change message would silently drop the change's
     notification. OR-accumulate instead, and track hadData before
     must-refetch clears state so subscribers still see the reset.

  #3 SubsetParams GET serialization dropped limit=0 and offset=0
     via falsy checks. Switched to explicit !== undefined guards.

  #4 Shape#requestedSubSnapshots dedup keyed on bigintSafeStringify,
     which preserves insertion order, so permutation-equivalent
     params produced different keys and re-execution fired the
     same snapshot N times. Added canonicalBigintSafeStringify to
     helpers.ts that recursively sorts object keys.

  #5 snakeToCamel collapsed runs of underscores into a single
     camelCase boundary, so user_id and user__id (distinct db
     columns) decoded to the same app key, corrupting rows with
     mapped values. snakeToCamel now preserves (n-1) literal
     underscores for a run of n, and camelToSnake's boundary
     regex was widened to ([a-z_])([A-Z]) so the round-trip is
     injective.

  #6 Shape#reexecuteSnapshots caught and discarded errors from
     stream.requestSnapshot, silently dropping failed sub-snapshot
     re-execution on shape rotation. Errors are now collected and
     the first one is surfaced via #error + #notify.

  #7 SnapshotTracker populated xmaxSnapshots and
     snapshotsByDatabaseLsn in addSnapshot but never cleaned them
     up — neither on removeSnapshot nor on addSnapshot with a
     repeated mark. A later shouldRejectMessage eviction loop
     would walk the stale reverse index and wrongly delete the
     current snapshot, allowing duplicate change messages to slip
     through. Stored databaseLsn on each entry and added
     #detachFromReverseIndexes that runs on both add (before
     overwriting) and remove.

  #8 Shape#awaitUpToDate never observed the stream's error state,
     so calling requestSnapshot on a terminally-errored stream
     would hang forever on the setInterval polling loop. The
     helper now checks #error / stream.error up front, subscribes
     to the stream's onError, and settles the internal promise
     via reject on any terminal error path.

Also:
  - vitest.pbt.config.ts — dedicated config that skips the
    real-Electric globalSetup and includes both model-based
    and pbt-micro test files.
  - bin/pbt-soak.sh — soak runner that loops PBT iterations
    with fresh seeds, captures counterexamples on failure.
  - test/pbt-micro.test.ts TARGET 4 (UpToDateTracker) restores
    real timers in afterEach so TARGET 12's setInterval doesn't
    hang when the suite runs end-to-end.
  - SPEC.md cross-references the L6 fetchSnapshotWithRetry PBT
    from the unconditional-409-cache-buster invariant.
  - model-based.test.ts gains response builders for update,
    delete, and mixed-batch 200s with lsn/op_position/txids
    headers for more realistic change sequences.

Verified with 319 unit tests, 44 PBT tests at 500 runs each
(and 2000-run soak), 62 column-mapper/snapshot-tracker tests,
typecheck clean, eslint clean, static-analysis tests clean.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant