Skip to content

MongoDB sessions: no resurrection on save, legacy purge, key escaping; CI - #16

Merged
taplin merged 1 commit into
mainfrom
mongodb-session-followups
Oct 4, 2026
Merged

taplin merged 1 commit into
mainfrom
mongodb-session-followups

Conversation

@taplin

@taplin taplin commented Oct 4, 2026

Copy link
Copy Markdown
Contributor

Follow-ups to #14 from the adversarial review, plus the repo's first CI.

MongoDB backend

  • Logout can't be undone by a racing save. save() now uses replaceOne(upsert: false). When nothing matched, it logs at debug level, since this is expected after a logout. Trade-off: a session whose create() insert failed, or that the TTL index already removed, is no longer re-created by the next save.

  • Legacy documents. setup() deletes documents left by the archived Perfect-Session-MongoDB: string token, string data, created/updated/idle present, and no expiresAt. This driver can't resume them, and the TTL index never expires them. The purge isn't in clean(), so during a rolling deploy it won't keep deleting sessions that old instances are still writing. Unrelated documents with a token field are left alone (tested). The README has a migration section (en + zh_CN).

  • Keys libmongoc won't store. Probed against MongoDB 8.3:

    • libmongoc rejects an empty key, which failed the whole write (only logged).
    • A key containing NUL was silently cut short.
    • $x and a.b are fine.

    Keys in data are now escaped at every depth: % becomes %25, NUL becomes %00, and "" becomes %. Other keys are stored unchanged, so data.<key> queries still work. Data that main's driver already stored with % in a key would read back differently, but no tagged release contains the MongoDB driver yet.

  • Perfect-MongoDB floor raised to from: "4.0.2".

CI and tests

  • New .github/workflows/ci.yml:
    • Linux (swift:6.4-resolute): every backend. SQLite runs through libsqlite3-dev, now that Build on Linux: add PerfectCSQLite system-library target Perfect-SQLite#23 builds on Linux. MongoDB, PostgreSQL, MySQL and Redis run against service containers.
    • macOS (macos-26): build plus the core and SQLite tests (no servers). It sets PKG_CONFIG_PATH for keg-only libpq/mysql-client.
  • The SQLite, PostgreSQL, MySQL and Redis suites are now .serialized, because each test sets the connector's global settings. The review saw the SQLite suite fail or segfault intermittently on main. Separately, 2 of 6 SQLite tests failed in parallel on Linux; with .serialized, 12 release runs on macOS passed.
  • The README (en + zh_CN) no longer calls SQLite macOS-only.

Verified

  • The three new server tests (empty key, save after destroy, legacy purge) fail on main and pass here.
  • Full suite on macOS, debug and release (-c release -Xswiftc -enable-testing), with MongoDB and SQLite.
  • Linux, Swift 6.4 on Ubuntu 26.04 in a container: all 56 tests against MongoDB 8, PostgreSQL 17, MySQL 8.4 and Redis 7, plus SQLite.
  • Not verified: this workflow hasn't run on GitHub before this PR, and I couldn't confirm the Swift version of the macos-26 runner's default Xcode.

🤖 Generated with Claude Code

…; CI

- save() now replaces with upsert: false, so a save racing destroy() (logout)
  can't bring the session back. When nothing matched it logs at debug level
  (it's expected after a logout). Trade-off: a session whose create() insert
  failed, or that the TTL removed, is no longer re-created by the next save.
- setup() deletes documents left by the archived Perfect-Session-MongoDB:
  string token, string data, created/updated/idle, no expiresAt. This driver
  can't resume them and the TTL index never expires them. The purge isn't in
  clean(), so during a rolling deploy it doesn't keep deleting sessions that
  old instances are still writing. README (en + zh_CN) has a migration note.
- Keys in session.data are escaped at every depth: "%" -> "%25",
  NUL -> "%00", "" -> "%". libmongoc rejects an empty key, which failed the
  whole write (only logged), and a key was cut short at NUL. Other keys are
  stored unchanged, so data.<key> queries still work. Data written by main's
  driver with "%" in a key would be read back differently, but no tagged
  release contains the MongoDB driver yet.
- Perfect-MongoDB floor raised to 4.0.2.
- GitHub Actions CI. Linux (swift:6.4-resolute) runs every backend: SQLite
  through libsqlite3-dev, now that Perfect-SQLite builds on Linux
  (PerfectlySoft/Perfect-SQLite#23), plus real MongoDB, PostgreSQL, MySQL and
  Redis services. macOS builds and runs the core and SQLite tests. README (en
  + zh_CN) no longer calls the SQLite backend macOS-only.
- The SQLite, PostgreSQL, MySQL and Redis suites are now serialized: each test
  sets the connector's global settings. The review saw the SQLite suite fail
  or segfault intermittently on main; 12 release runs here passed.

The three new server tests (empty key, save after destroy, legacy purge) fail
on main and pass here against MongoDB 8.3. The full suite passes in macOS
debug and release, and on Linux (Swift 6.4, Ubuntu 26.04 container) with SQLite
and against MongoDB 8, PostgreSQL 17, MySQL 8.4 and Redis 7.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@taplin
taplin merged commit ce904cd into main Oct 4, 2026
4 checks passed
@taplin
taplin deleted the mongodb-session-followups branch October 4, 2026 18:19
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