-
Notifications
You must be signed in to change notification settings - Fork 4
Open
Description
Problem
The current implementation of the cqrs.outbox.sqlalchemy module has several architectural limitations:
- MySQL Vendor-lock: Reliance on the func.UUID_TO_BIN function makes the library incompatible with PostgreSQL or SQLite.
- Migration Issues (Alembic): The OutboxModel is bound to the library's internal Base. This complicates migration generation in user applications since Alembic cannot detect this table in the target_metadata.
- Index Performance: Using random UUID v4 as a Primary Key (or part of a composite index) causes B-Tree index fragmentation, degrading INSERT performance over time.
- Hard Dependency: SQLAlchemy is currently a mandatory dependency, even if the user intends to use a different backend or strictly in-memory implementation.
Solution
This PR proposes a comprehensive refactoring of the Outbox module:
- Transition to Mixin Architecture
- Replaced the hardcoded OutboxModel with OutboxModelMixin.
- Users now define the model themselves by inheriting from their own DeclarativeBase and the provided mixin.
- This resolves Alembic integration issues and allows customization of tablename.
- Cross-Database Compatibility (PostgreSQL support)
- Removed dependency on the MySQL-specific UUID_TO_BIN function.
- Implemented a custom BinaryUUID type (TypeDecorator).
- PostgreSQL: Uses the native UUID type.
- MySQL/SQLite: Uses optimized BINARY(16) storage.
- Performance Optimization (UUID v7)
- Added uuid6 dependency.
- Switched default event_id generation from uuid4 to uuid7.
- UUID v7 is time-ordered (monotonically increasing), ensuring sequential writes to the B-Tree index and eliminating fragmentation.
- Optional SQLAlchemy Dependency
- Moved sqlalchemy to optional-dependencies (pip install python-cqrs[sqlalchemy]).
- Wrapped internal library imports in try-except blocks to prevent crashes when the driver is not installed.
New Usage Example
from sqlalchemy.orm import DeclarativeBase
from cqrs.outbox import OutboxModelMixin
# Define the model in the user application
class Base(DeclarativeBase):
pass
class MyOutbox(Base, OutboxModelMixin):
__tablename__ = "outbox_events"
# Initialize the repository
repo = SqlAlchemyOutboxedEventRepository(
session=session,
outbox_model=MyOutbox # Pass the model class
)Checklist
- Implement OutboxModelMixin.
- Implement BinaryUUID for PostgreSQL and MySQL compatibility.
- Switch ID generation to uuid7.
- Make sqlalchemy an optional dependency.
- Update tests (using testcontainers or mocks).
- Update documentation (README).
vadikko2
Metadata
Metadata
Assignees
Labels
No labels