Skip to content

Conversation

@oliverbarnes
Copy link
Contributor

@oliverbarnes oliverbarnes commented Jun 25, 2025

Closes #464

Demo on https://github.com/oliverbarnes/pavex_mysql_sessions_demo

Follows the Postgres and SQLite session store implementations.

Key differences below, Claude generated (let me know if it's a bit much with the emojis and all):

🗄️ Database Schema Differences

MySQL

CREATE TABLE IF NOT EXISTS sessions (
    id CHAR(36) PRIMARY KEY,           -- UUID as string
    deadline BIGINT NOT NULL,          -- Unix timestamp (seconds)
    state JSON NOT NULL,               -- JSON column type
    INDEX idx_sessions_deadline (deadline)
);

PostgreSQL

CREATE TABLE IF NOT EXISTS sessions (
    id UUID PRIMARY KEY,               -- Native UUID type
    deadline TIMESTAMPTZ NOT NULL,     -- Timezone-aware timestamp
    state JSONB NOT NULL               -- Binary JSON (more efficient)
);
-- Separate index creation with conditional logic
CREATE INDEX idx_sessions_deadline ON sessions(deadline);

Time Handling Differences

MySQL

  • Uses Unix timestamps (BIGINT) for deadline storage
  • Uses UNIX_TIMESTAMP() function for current time comparisons
  • Example: WHERE deadline > UNIX_TIMESTAMP()

PostgreSQL

  • Uses native timestamp with timezone (TIMESTAMPTZ)
  • Uses (now() AT TIME ZONE 'UTC') for current time comparisons
  • Example: WHERE deadline > (now() AT TIME ZONE 'UTC')

🔧 SQL Parameter Binding

MySQL

  • Uses positional parameters with ? placeholders
  • Example: INSERT INTO sessions (id, deadline, state) VALUES (?, ?, ?)

PostgreSQL

  • Uses numbered parameters with $1, $2, $3 placeholders
  • Example: INSERT INTO sessions (id, deadline, state) VALUES ($1, $2, $3)

🚨 Error Code Handling

MySQL

// MySQL error code for duplicate entry
if e.number() == 1062 {
    return Err(DuplicateIdError { id: id.to_owned() });
}

PostgreSQL

// PostgreSQL error code for unique constraint violation
if e.code() == "23505" && e.column() == Some("id") {
    return Err(DuplicateIdError { id: id.to_owned() });
}

📦 Framework Integration

MySQL

  • No dedicated kit - users must manually register components
  • Only exports MySqlSessionStore
  • Users need to handle pool registration and session setup manually

PostgreSQL

  • Has PostgresSessionKit - provides convenient registration
  • Exports both PostgresSessionStore and PostgresSessionKit
  • Kit handles automatic component registration with PostgresSessionKit::new().register(&mut bp)

🗂️ JSON Storage

MySQL

  • Uses JSON column type (MySQL 5.7.8+)
  • Text-based JSON storage
  • MySQL 8.0+ recommended for better performance

PostgreSQL

  • Uses JSONB column type (binary JSON)
  • More efficient storage and querying
  • Built-in JSON operators and indexing support

🛠️ Migration Complexity

MySQL

  • Simple: Single CREATE TABLE IF NOT EXISTS statement
  • Index created inline with table

PostgreSQL

  • Complex: Uses PL/pgSQL block for conditional index creation
  • Checks pg_indexes system table to avoid duplicate indexes
  • More robust but verbose migration logic

📋 Version Requirements

MySQL

  • Requires MySQL 5.7.8+ or MariaDB 10.2+ for JSON support
  • MySQL 8.0+ recommended for optimal JSON performance

PostgreSQL

  • Standard PostgreSQL features (UUID, JSONB, TIMESTAMPTZ)
  • More predictable cross-version compatibility

@oliverbarnes
Copy link
Contributor Author

Looking into the build errors.

@oliverbarnes
Copy link
Contributor Author

@LukeMathWalker from what I gathered it's safe to ignore RUSTSEC-2023-0071, while there's no patch available. This fixes https://github.com/LukeMathWalker/pavex/actions/runs/16118570900/job/45478226401?pr=499.

I've gone ahead and submitted the update to deny.toml, let me know if you think otherwise? I'm looking into the workspace hack issue

@oliverbarnes
Copy link
Contributor Author

Conflicts resolved and build fixed.

@LukeMathWalker
Copy link
Owner

@LukeMathWalker from what I gathered it's safe to ignore RUSTSEC-2023-0071, while there's no patch available. This fixes https://github.com/LukeMathWalker/pavex/actions/runs/16118570900/job/45478226401?pr=499.

I've gone ahead and submitted the update to deny.toml, let me know if you think otherwise? I'm looking into the workspace hack issue

I don't particularly love it because it doesn't allow us to distinguish between silencing the advisory for that specific link in our dependency tree and silencing the advisory for any usage of the rsa crate.
But that's a limitation of the tool, so for now we'll live with it.

@oliverbarnes
Copy link
Contributor Author

@LukeMathWalker from what I gathered it's safe to ignore RUSTSEC-2023-0071, while there's no patch available. This fixes https://github.com/LukeMathWalker/pavex/actions/runs/16118570900/job/45478226401?pr=499.
I've gone ahead and submitted the update to deny.toml, let me know if you think otherwise? I'm looking into the workspace hack issue

I don't particularly love it because it doesn't allow us to distinguish between silencing the advisory for that specific link in our dependency tree and silencing the advisory for any usage of the rsa crate. But that's a limitation of the tool, so for now we'll live with it.

Agree, I don't love it at all. But don't see an alternative

# Conflicts:
#	libs/Cargo.lock
#	libs/pavex_session_sqlx/Cargo.toml
#	libs/px_workspace_hack/Cargo.toml
@oliverbarnes
Copy link
Contributor Author

After merging main, fixing conflicts and running hakari, I see a bunch of packages' Cargo.toml updated with

px_workspace_hack = { version = "0.1", path = "../px_workspace_hack" }

And the top level libs/Cargo.toml has several px_workspace_hack that aren't there on latest main.

I'm wondering if the conflict resolution regressed the workspace hack somehow. Gonna investigate and update here.

@LukeMathWalker
Copy link
Owner

After merging main, fixing conflicts and running hakari, I see a bunch of packages' Cargo.toml updated with

px_workspace_hack = { version = "0.1", path = "../px_workspace_hack" }

And the top level libs/Cargo.toml has several px_workspace_hack that aren't there on latest main.

I'm wondering if the conflict resolution regressed the workspace hack somehow. Gonna investigate and update here.

I had to merge #512 to re-enable the hack after the release. That should solve the issue.

# Conflicts:
#	libs/Cargo.lock
#	libs/pavex_bp_schema/Cargo.toml
#	libs/pavex_tracing/Cargo.toml
#	libs/px_workspace_hack/Cargo.toml
@oliverbarnes
Copy link
Contributor Author

👍 I see, merged!

Comment on lines 568 to 576
// Verify the original data is still there (not overwritten)
let loaded_after = store.load(&session_id).await.unwrap().unwrap();
for (key, expected_value) in &state {
assert_eq!(
loaded_after.state.get(key).unwrap(),
expected_value,
"Original data should be preserved when session exists"
);
}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's not the property we want. It just happens to work because you have created the conflicted state starting from the existing one.
Let's modify the test case to remove this overlap and check that we don't have anything else in the new state beyond the newly created session state.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Arg, well caught. Will fix

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Added some comments to the implementation for clarity on the decision to keep simple upserts.

@oliverbarnes
Copy link
Contributor Author

Build is failing due to RUSTSEC-2025-0047, which has been fixed in slab v0.4.11. Looks like it's a dependency of Tokio, but there's no new release for it with the new slab.

I tried adding it explicitly to the top level Cargo.toml, but Cargo.lock doesn't seem to update after building.

I suspect I may be missing something about Rust dependency management here...

@LukeMathWalker
Copy link
Owner

Solved the issue and made a few final tweaks in #532. Merged!

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.

feat: Add a MySQL-based session storage backend to pavex_session_sqlx

2 participants