eventsource-py 0.2.0__tar.gz → 0.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- eventsource_py-0.3.0/CHANGELOG.md +372 -0
- eventsource_py-0.3.0/PKG-INFO +273 -0
- eventsource_py-0.3.0/README.md +203 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/docs/adrs/0004-projection-error-handling.md +55 -56
- eventsource_py-0.3.0/docs/api/aggregates.md +548 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/docs/api/bus.md +109 -26
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/docs/api/index.md +104 -1
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/docs/api/observability.md +30 -0
- eventsource_py-0.3.0/docs/api/projections.md +777 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/docs/api/snapshots.md +127 -15
- eventsource_py-0.3.0/docs/api/stores.md +1252 -0
- eventsource_py-0.3.0/docs/api/subscriptions.md +2155 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/docs/architecture.md +30 -11
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/docs/development/code-structure.md +1 -1
- eventsource_py-0.3.0/docs/examples/projections.md +407 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/docs/examples/sqlite-usage.md +35 -8
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/docs/faq.md +138 -9
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/docs/getting-started.md +64 -27
- eventsource_py-0.3.0/docs/guides/event-bus.md +391 -0
- eventsource_py-0.3.0/docs/guides/kubernetes-deployment.md +1065 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/docs/guides/observability.md +267 -48
- eventsource_py-0.3.0/docs/guides/repository-pattern.md +633 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/docs/guides/snapshotting-migration.md +21 -13
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/docs/guides/snapshotting.md +12 -4
- eventsource_py-0.3.0/docs/guides/subscription-migration.md +433 -0
- eventsource_py-0.3.0/docs/guides/subscriptions.md +683 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/docs/index.md +4 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/docs/installation.md +1 -0
- eventsource_py-0.3.0/docs/migration/README.md +123 -0
- eventsource_py-0.3.0/docs/migration/api-reference.md +712 -0
- eventsource_py-0.3.0/docs/migration/architecture.md +311 -0
- eventsource_py-0.3.0/docs/migration/migration-guide.md +488 -0
- eventsource_py-0.3.0/docs/migration/monitoring.md +596 -0
- eventsource_py-0.3.0/docs/migration/runbook.md +610 -0
- eventsource_py-0.3.0/docs/migration/troubleshooting.md +603 -0
- eventsource_py-0.3.0/docs/tutorials/01-introduction.md +149 -0
- eventsource_py-0.3.0/docs/tutorials/02-first-event.md +243 -0
- eventsource_py-0.3.0/docs/tutorials/03-first-aggregate.md +425 -0
- eventsource_py-0.3.0/docs/tutorials/04-event-stores.md +263 -0
- eventsource_py-0.3.0/docs/tutorials/05-repositories.md +315 -0
- eventsource_py-0.3.0/docs/tutorials/06-projections.md +291 -0
- eventsource_py-0.3.0/docs/tutorials/07-event-bus.md +296 -0
- eventsource_py-0.3.0/docs/tutorials/08-testing.md +487 -0
- eventsource_py-0.3.0/docs/tutorials/09-error-handling.md +344 -0
- eventsource_py-0.3.0/docs/tutorials/10-checkpoints.md +127 -0
- eventsource_py-0.3.0/docs/tutorials/11-postgresql.md +456 -0
- eventsource_py-0.3.0/docs/tutorials/12-sqlite.md +545 -0
- eventsource_py-0.3.0/docs/tutorials/13-subscriptions.md +659 -0
- eventsource_py-0.3.0/docs/tutorials/14-snapshotting.md +340 -0
- eventsource_py-0.3.0/docs/tutorials/15-production.md +770 -0
- eventsource_py-0.3.0/docs/tutorials/16-multi-tenancy.md +502 -0
- eventsource_py-0.3.0/docs/tutorials/17-redis.md +642 -0
- eventsource_py-0.3.0/docs/tutorials/18-kafka.md +601 -0
- eventsource_py-0.3.0/docs/tutorials/19-rabbitmq.md +865 -0
- eventsource_py-0.3.0/docs/tutorials/20-observability.md +680 -0
- eventsource_py-0.3.0/docs/tutorials/21-advanced-aggregates.md +2323 -0
- eventsource_py-0.3.0/docs/tutorials/exercises/solutions/04-1.py +144 -0
- eventsource_py-0.3.0/docs/tutorials/exercises/solutions/05-1.py +188 -0
- eventsource_py-0.3.0/docs/tutorials/exercises/solutions/06-1.py +309 -0
- eventsource_py-0.3.0/docs/tutorials/exercises/solutions/07-1.py +206 -0
- eventsource_py-0.3.0/docs/tutorials/exercises/solutions/08-1.py +515 -0
- eventsource_py-0.3.0/docs/tutorials/exercises/solutions/09-1.py +199 -0
- eventsource_py-0.3.0/docs/tutorials/exercises/solutions/10-1.py +257 -0
- eventsource_py-0.3.0/docs/tutorials/exercises/solutions/11-1.py +325 -0
- eventsource_py-0.3.0/docs/tutorials/exercises/solutions/12-1.py +340 -0
- eventsource_py-0.3.0/docs/tutorials/exercises/solutions/13-1.py +337 -0
- eventsource_py-0.3.0/docs/tutorials/exercises/solutions/14-1.py +144 -0
- eventsource_py-0.3.0/docs/tutorials/exercises/solutions/16-1.py +477 -0
- eventsource_py-0.3.0/docs/tutorials/exercises/solutions/18-1.py +270 -0
- eventsource_py-0.3.0/docs/tutorials/exercises/solutions/19-1.py +336 -0
- eventsource_py-0.3.0/docs/tutorials/exercises/solutions/20-1.py +350 -0
- eventsource_py-0.3.0/docs/tutorials/exercises/solutions/21-1.py +1022 -0
- eventsource_py-0.3.0/docs/tutorials/index.md +216 -0
- eventsource_py-0.3.0/examples/projection_example.py +600 -0
- eventsource_py-0.3.0/examples/subscriptions/README.md +331 -0
- eventsource_py-0.3.0/examples/subscriptions/__init__.py +14 -0
- eventsource_py-0.3.0/examples/subscriptions/basic_projection.py +450 -0
- eventsource_py-0.3.0/examples/subscriptions/multi_subscriber.py +766 -0
- eventsource_py-0.3.0/examples/subscriptions/resilient_projection.py +539 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/mkdocs.yml +28 -2
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/pyproject.toml +4 -2
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/__init__.py +5 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/aggregates/repository.py +41 -237
- eventsource_py-0.3.0/src/eventsource/aggregates/snapshot_manager.py +320 -0
- eventsource_py-0.3.0/src/eventsource/aggregates/task_manager.py +210 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/bus/kafka.py +640 -207
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/bus/memory.py +41 -103
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/bus/rabbitmq.py +120 -142
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/bus/redis.py +37 -99
- eventsource_py-0.3.0/src/eventsource/handlers/__init__.py +48 -0
- eventsource_py-0.3.0/src/eventsource/handlers/adapter.py +205 -0
- eventsource_py-0.3.0/src/eventsource/handlers/registry.py +419 -0
- eventsource_py-0.3.0/src/eventsource/locks/__init__.py +48 -0
- eventsource_py-0.3.0/src/eventsource/locks/postgresql.py +520 -0
- eventsource_py-0.3.0/src/eventsource/migration/__init__.py +201 -0
- eventsource_py-0.3.0/src/eventsource/migration/bulk_copier.py +591 -0
- eventsource_py-0.3.0/src/eventsource/migration/consistency.py +850 -0
- eventsource_py-0.3.0/src/eventsource/migration/coordinator.py +1692 -0
- eventsource_py-0.3.0/src/eventsource/migration/cutover.py +596 -0
- eventsource_py-0.3.0/src/eventsource/migration/dual_write.py +532 -0
- eventsource_py-0.3.0/src/eventsource/migration/exceptions.py +1516 -0
- eventsource_py-0.3.0/src/eventsource/migration/metrics.py +818 -0
- eventsource_py-0.3.0/src/eventsource/migration/models.py +1144 -0
- eventsource_py-0.3.0/src/eventsource/migration/position_mapper.py +639 -0
- eventsource_py-0.3.0/src/eventsource/migration/repositories/__init__.py +73 -0
- eventsource_py-0.3.0/src/eventsource/migration/repositories/audit_log.py +510 -0
- eventsource_py-0.3.0/src/eventsource/migration/repositories/migration.py +831 -0
- eventsource_py-0.3.0/src/eventsource/migration/repositories/position_mapping.py +899 -0
- eventsource_py-0.3.0/src/eventsource/migration/repositories/routing.py +683 -0
- eventsource_py-0.3.0/src/eventsource/migration/router.py +772 -0
- eventsource_py-0.3.0/src/eventsource/migration/status_streamer.py +525 -0
- eventsource_py-0.3.0/src/eventsource/migration/subscription_migrator.py +875 -0
- eventsource_py-0.3.0/src/eventsource/migration/sync_lag_tracker.py +526 -0
- eventsource_py-0.3.0/src/eventsource/migration/write_pause.py +533 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/migrations/__init__.py +3 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/migrations/schemas/all.sql +2 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/migrations/schemas/sqlite_all.sql +1 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/migrations/templates/checkpoints.sql +11 -0
- eventsource_py-0.3.0/src/eventsource/migrations/templates/migration.sql +320 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/migrations/templates/sqlite/checkpoints.sql +4 -0
- eventsource_py-0.3.0/src/eventsource/migrations/updates/001_add_global_position.sql +38 -0
- eventsource_py-0.3.0/src/eventsource/migrations/updates/001_add_global_position_sqlite.sql +18 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/observability/__init__.py +56 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/observability/attributes.py +136 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/projections/base.py +133 -256
- eventsource_py-0.3.0/src/eventsource/projections/checkpoint_manager.py +227 -0
- eventsource_py-0.3.0/src/eventsource/projections/dlq_manager.py +214 -0
- eventsource_py-0.3.0/src/eventsource/projections/retry.py +288 -0
- eventsource_py-0.3.0/src/eventsource/readmodels/__init__.py +113 -0
- eventsource_py-0.3.0/src/eventsource/readmodels/base.py +251 -0
- eventsource_py-0.3.0/src/eventsource/readmodels/exceptions.py +123 -0
- eventsource_py-0.3.0/src/eventsource/readmodels/in_memory.py +537 -0
- eventsource_py-0.3.0/src/eventsource/readmodels/postgresql.py +781 -0
- eventsource_py-0.3.0/src/eventsource/readmodels/projection.py +351 -0
- eventsource_py-0.3.0/src/eventsource/readmodels/query.py +362 -0
- eventsource_py-0.3.0/src/eventsource/readmodels/repository.py +402 -0
- eventsource_py-0.3.0/src/eventsource/readmodels/schema.py +462 -0
- eventsource_py-0.3.0/src/eventsource/readmodels/sqlite.py +852 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/repositories/checkpoint.py +272 -2
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/repositories/dlq.py +116 -97
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/repositories/outbox.py +110 -73
- eventsource_py-0.3.0/src/eventsource/snapshots/strategies.py +450 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/stores/__init__.py +11 -0
- eventsource_py-0.3.0/src/eventsource/stores/_type_converter.py +317 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/stores/in_memory.py +18 -1
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/stores/interface.py +35 -1
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/stores/postgresql.py +54 -124
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/stores/sqlite.py +111 -66
- eventsource_py-0.3.0/src/eventsource/subscriptions/__init__.py +345 -0
- eventsource_py-0.3.0/src/eventsource/subscriptions/config.py +285 -0
- eventsource_py-0.3.0/src/eventsource/subscriptions/coordination.py +1419 -0
- eventsource_py-0.3.0/src/eventsource/subscriptions/error_handling.py +1043 -0
- eventsource_py-0.3.0/src/eventsource/subscriptions/exceptions.py +62 -0
- eventsource_py-0.3.0/src/eventsource/subscriptions/filtering.py +484 -0
- eventsource_py-0.3.0/src/eventsource/subscriptions/flow_control.py +438 -0
- eventsource_py-0.3.0/src/eventsource/subscriptions/health.py +872 -0
- eventsource_py-0.3.0/src/eventsource/subscriptions/health_provider.py +551 -0
- eventsource_py-0.3.0/src/eventsource/subscriptions/lifecycle.py +364 -0
- eventsource_py-0.3.0/src/eventsource/subscriptions/manager.py +1283 -0
- eventsource_py-0.3.0/src/eventsource/subscriptions/metrics.py +571 -0
- eventsource_py-0.3.0/src/eventsource/subscriptions/pause_resume.py +278 -0
- eventsource_py-0.3.0/src/eventsource/subscriptions/registry.py +186 -0
- eventsource_py-0.3.0/src/eventsource/subscriptions/retry.py +643 -0
- eventsource_py-0.3.0/src/eventsource/subscriptions/runners/__init__.py +19 -0
- eventsource_py-0.3.0/src/eventsource/subscriptions/runners/catchup.py +648 -0
- eventsource_py-0.3.0/src/eventsource/subscriptions/runners/live.py +783 -0
- eventsource_py-0.3.0/src/eventsource/subscriptions/shutdown.py +1535 -0
- eventsource_py-0.3.0/src/eventsource/subscriptions/subscriber.py +468 -0
- eventsource_py-0.3.0/src/eventsource/subscriptions/subscription.py +754 -0
- eventsource_py-0.3.0/src/eventsource/subscriptions/transition.py +555 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/conftest.py +2 -1
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/integration/bus/test_kafka.py +5 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/integration/bus/test_rabbitmq.py +10 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/integration/conftest.py +1 -0
- eventsource_py-0.3.0/tests/integration/locks/__init__.py +1 -0
- eventsource_py-0.3.0/tests/integration/locks/test_postgresql_locks_integration.py +450 -0
- eventsource_py-0.3.0/tests/integration/migrations/__init__.py +1 -0
- eventsource_py-0.3.0/tests/integration/migrations/test_migration_schema_postgresql.py +830 -0
- eventsource_py-0.3.0/tests/integration/readmodels/__init__.py +6 -0
- eventsource_py-0.3.0/tests/integration/readmodels/conftest.py +190 -0
- eventsource_py-0.3.0/tests/integration/readmodels/test_enhanced_features.py +851 -0
- eventsource_py-0.3.0/tests/integration/readmodels/test_projection.py +1242 -0
- eventsource_py-0.3.0/tests/integration/readmodels/test_repositories.py +914 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/integration/repositories/test_dlq.py +14 -14
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/integration/repositories/test_outbox.py +10 -10
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/integration/stores/test_postgresql.py +154 -0
- eventsource_py-0.3.0/tests/integration/subscriptions/__init__.py +11 -0
- eventsource_py-0.3.0/tests/integration/subscriptions/conftest.py +371 -0
- eventsource_py-0.3.0/tests/integration/subscriptions/test_advanced_features.py +1505 -0
- eventsource_py-0.3.0/tests/integration/subscriptions/test_catchup.py +368 -0
- eventsource_py-0.3.0/tests/integration/subscriptions/test_full_flow.py +664 -0
- eventsource_py-0.3.0/tests/integration/subscriptions/test_live.py +395 -0
- eventsource_py-0.3.0/tests/integration/subscriptions/test_resilience.py +1459 -0
- eventsource_py-0.3.0/tests/integration/subscriptions/test_transition.py +377 -0
- eventsource_py-0.3.0/tests/locks/__init__.py +1 -0
- eventsource_py-0.3.0/tests/locks/test_postgresql_locks.py +188 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/repositories/test_sqlite_repos.py +66 -66
- eventsource_py-0.3.0/tests/stores/test_read_all_tenant_filter.py +437 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/unit/aggregates/test_repository_snapshot.py +34 -58
- eventsource_py-0.3.0/tests/unit/migration/__init__.py +1 -0
- eventsource_py-0.3.0/tests/unit/migration/test_audit_log_repository.py +885 -0
- eventsource_py-0.3.0/tests/unit/migration/test_bulk_copier.py +945 -0
- eventsource_py-0.3.0/tests/unit/migration/test_chaos.py +1812 -0
- eventsource_py-0.3.0/tests/unit/migration/test_consistency_verifier.py +1077 -0
- eventsource_py-0.3.0/tests/unit/migration/test_coordinator.py +1140 -0
- eventsource_py-0.3.0/tests/unit/migration/test_coordinator_dual_write.py +986 -0
- eventsource_py-0.3.0/tests/unit/migration/test_coordinator_subscriptions.py +986 -0
- eventsource_py-0.3.0/tests/unit/migration/test_cutover_manager.py +1340 -0
- eventsource_py-0.3.0/tests/unit/migration/test_dual_write.py +888 -0
- eventsource_py-0.3.0/tests/unit/migration/test_error_classification.py +874 -0
- eventsource_py-0.3.0/tests/unit/migration/test_exceptions.py +480 -0
- eventsource_py-0.3.0/tests/unit/migration/test_final_integration.py +2302 -0
- eventsource_py-0.3.0/tests/unit/migration/test_load_benchmarks.py +1484 -0
- eventsource_py-0.3.0/tests/unit/migration/test_migration_metrics.py +964 -0
- eventsource_py-0.3.0/tests/unit/migration/test_migration_repository.py +1044 -0
- eventsource_py-0.3.0/tests/unit/migration/test_models.py +1071 -0
- eventsource_py-0.3.0/tests/unit/migration/test_phase2_integration.py +1771 -0
- eventsource_py-0.3.0/tests/unit/migration/test_phase3_integration.py +2193 -0
- eventsource_py-0.3.0/tests/unit/migration/test_position_mapper.py +904 -0
- eventsource_py-0.3.0/tests/unit/migration/test_position_mapping_repository.py +1102 -0
- eventsource_py-0.3.0/tests/unit/migration/test_router.py +1350 -0
- eventsource_py-0.3.0/tests/unit/migration/test_routing_repository.py +1023 -0
- eventsource_py-0.3.0/tests/unit/migration/test_status_streamer.py +963 -0
- eventsource_py-0.3.0/tests/unit/migration/test_subscription_migrator.py +1108 -0
- eventsource_py-0.3.0/tests/unit/migration/test_sync_lag_tracker.py +1027 -0
- eventsource_py-0.3.0/tests/unit/migration/test_write_pause.py +876 -0
- eventsource_py-0.3.0/tests/unit/migrations/test_migration_schema.py +427 -0
- eventsource_py-0.3.0/tests/unit/readmodels/__init__.py +1 -0
- eventsource_py-0.3.0/tests/unit/readmodels/test_base.py +324 -0
- eventsource_py-0.3.0/tests/unit/readmodels/test_exports.py +90 -0
- eventsource_py-0.3.0/tests/unit/readmodels/test_handler_integration.py +445 -0
- eventsource_py-0.3.0/tests/unit/readmodels/test_in_memory.py +948 -0
- eventsource_py-0.3.0/tests/unit/readmodels/test_optimistic_locking.py +346 -0
- eventsource_py-0.3.0/tests/unit/readmodels/test_postgresql.py +531 -0
- eventsource_py-0.3.0/tests/unit/readmodels/test_projection.py +856 -0
- eventsource_py-0.3.0/tests/unit/readmodels/test_query.py +317 -0
- eventsource_py-0.3.0/tests/unit/readmodels/test_repository_protocol.py +108 -0
- eventsource_py-0.3.0/tests/unit/readmodels/test_schema.py +631 -0
- eventsource_py-0.3.0/tests/unit/readmodels/test_soft_delete.py +525 -0
- eventsource_py-0.3.0/tests/unit/readmodels/test_sqlite.py +698 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/unit/repositories/test_checkpoint_tracing.py +3 -0
- eventsource_py-0.3.0/tests/unit/stores/test_type_converter.py +333 -0
- eventsource_py-0.3.0/tests/unit/subscriptions/__init__.py +1 -0
- eventsource_py-0.3.0/tests/unit/subscriptions/test_backpressure.py +670 -0
- eventsource_py-0.3.0/tests/unit/subscriptions/test_coordination.py +1629 -0
- eventsource_py-0.3.0/tests/unit/subscriptions/test_drain.py +744 -0
- eventsource_py-0.3.0/tests/unit/subscriptions/test_error_handling.py +840 -0
- eventsource_py-0.3.0/tests/unit/subscriptions/test_filtering.py +713 -0
- eventsource_py-0.3.0/tests/unit/subscriptions/test_health.py +981 -0
- eventsource_py-0.3.0/tests/unit/subscriptions/test_health_api.py +472 -0
- eventsource_py-0.3.0/tests/unit/subscriptions/test_manager_pause_resume.py +678 -0
- eventsource_py-0.3.0/tests/unit/subscriptions/test_metrics.py +689 -0
- eventsource_py-0.3.0/tests/unit/subscriptions/test_pause_resume.py +557 -0
- eventsource_py-0.3.0/tests/unit/subscriptions/test_retry.py +889 -0
- eventsource_py-0.3.0/tests/unit/subscriptions/test_shutdown.py +2720 -0
- eventsource_py-0.3.0/tests/unit/subscriptions/test_subscriber.py +832 -0
- eventsource_py-0.3.0/tests/unit/subscriptions/test_subscription_state.py +1105 -0
- eventsource_py-0.3.0/tests/unit/subscriptions/test_tenant_filtering.py +459 -0
- eventsource_py-0.3.0/tests/unit/test_catchup_runner.py +831 -0
- eventsource_py-0.3.0/tests/unit/test_checkpoint_position.py +484 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/unit/test_checkpoint_repository.py +2 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/unit/test_dlq_repository.py +64 -64
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/unit/test_edge_cases.py +6 -6
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/unit/test_event_store_interface.py +3 -0
- eventsource_py-0.3.0/tests/unit/test_eventstore_global_position.py +299 -0
- eventsource_py-0.3.0/tests/unit/test_live_runner.py +855 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/unit/test_outbox_repository.py +64 -64
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/unit/test_postgresql_event_store.py +56 -54
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/unit/test_rabbitmq_event_bus.py +155 -115
- eventsource_py-0.3.0/tests/unit/test_subscription_config.py +539 -0
- eventsource_py-0.3.0/tests/unit/test_subscription_manager.py +1490 -0
- eventsource_py-0.3.0/tests/unit/test_transition.py +971 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/uv.lock +1 -1
- eventsource_py-0.2.0/CHANGELOG.md +0 -135
- eventsource_py-0.2.0/PKG-INFO +0 -340
- eventsource_py-0.2.0/README.md +0 -270
- eventsource_py-0.2.0/docs/api/aggregates.md +0 -576
- eventsource_py-0.2.0/docs/api/projections.md +0 -514
- eventsource_py-0.2.0/docs/api/stores.md +0 -666
- eventsource_py-0.2.0/docs/examples/projections.md +0 -682
- eventsource_py-0.2.0/examples/projection_example.py +0 -511
- eventsource_py-0.2.0/tests/integration/observability/test_tracing_performance.py +0 -713
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/.github/workflows/ci.yml +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/.github/workflows/docs.yml +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/.github/workflows/release.yml +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/.gitignore +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/.pre-commit-config.yaml +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/LICENSE +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/RELEASING.md +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/docker-compose.test.yml +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/docs/adrs/0000-template.md +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/docs/adrs/0001-async-first-design.md +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/docs/adrs/0002-pydantic-event-models.md +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/docs/adrs/0003-optimistic-locking.md +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/docs/adrs/0005-api-design-patterns.md +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/docs/adrs/0006-event-registry-serialization.md +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/docs/adrs/0007-remove-sync-event-store.md +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/docs/adrs/0008-kafka-event-bus-integration.md +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/docs/adrs/index.md +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/docs/api/events.md +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/docs/development/testing.md +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/docs/examples/basic-order.md +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/docs/examples/multi-tenant.md +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/docs/examples/snapshotting.md +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/docs/examples/testing.md +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/docs/guides/authentication.md +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/docs/guides/error-handling.md +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/docs/guides/fanout-exchange.md +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/docs/guides/kafka-event-bus.md +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/docs/guides/kafka-metrics.md +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/docs/guides/multi-tenant.md +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/docs/guides/production.md +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/docs/guides/sqlite-backend.md +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/docs/infrastructure-tracking.md +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/examples/__init__.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/examples/aggregate_example.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/examples/basic_usage.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/py.typed +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/scripts/validate_examples.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/aggregates/__init__.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/aggregates/base.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/bus/__init__.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/bus/interface.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/config.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/events/__init__.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/events/base.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/events/registry.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/exceptions.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/migrations/SCHEMA_DESIGN.md +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/migrations/schemas/checkpoints.sql +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/migrations/schemas/dlq.sql +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/migrations/schemas/events.sql +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/migrations/schemas/events_partitioned.sql +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/migrations/schemas/outbox.sql +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/migrations/schemas/snapshots.sql +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/migrations/templates/alembic/all_tables.py.template +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/migrations/templates/alembic/checkpoints.py.template +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/migrations/templates/alembic/dlq.py.template +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/migrations/templates/alembic/events.py.template +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/migrations/templates/alembic/outbox.py.template +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/migrations/templates/dlq.sql +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/migrations/templates/events.sql +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/migrations/templates/events_partitioned.sql +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/migrations/templates/outbox.sql +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/migrations/templates/snapshots.sql +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/migrations/templates/sqlite/dlq.sql +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/migrations/templates/sqlite/events.sql +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/migrations/templates/sqlite/outbox.sql +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/migrations/templates/sqlite/snapshots.sql +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/observability/tracing.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/projections/__init__.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/projections/coordinator.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/projections/decorators.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/projections/protocols.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/protocols.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/py.typed +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/repositories/__init__.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/repositories/_connection.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/repositories/_json.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/snapshots/__init__.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/snapshots/exceptions.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/snapshots/in_memory.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/snapshots/interface.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/snapshots/postgresql.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/snapshots/sqlite.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/stores/_compat.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/src/eventsource/types.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/__init__.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/benchmarks/__init__.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/benchmarks/conftest.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/benchmarks/test_event_store.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/benchmarks/test_projections.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/benchmarks/test_repositories.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/benchmarks/test_serialization.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/fixtures/__init__.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/fixtures/aggregates.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/fixtures/events.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/integration/__init__.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/integration/bus/__init__.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/integration/bus/test_redis.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/integration/e2e/__init__.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/integration/e2e/test_full_flow.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/integration/observability/__init__.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/integration/observability/conftest.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/integration/observability/test_distributed_tracing.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/integration/observability/test_tracing_integration.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/integration/projections/__init__.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/integration/projections/test_database_projection.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/integration/repositories/__init__.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/integration/repositories/test_checkpoint.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/integration/stores/__init__.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/repositories/__init__.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/stores/__init__.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/stores/test_sqlite_event_store.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/unit/__init__.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/unit/aggregates/__init__.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/unit/aggregates/test_aggregate_snapshot_methods.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/unit/aggregates/test_repository_tracing.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/unit/bus/__init__.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/unit/bus/test_eventbus_tracing_patterns.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/unit/bus/test_rabbitmq_tracing.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/unit/migrations/__init__.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/unit/migrations/test_sqlite_snapshot_schema.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/unit/observability/__init__.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/unit/observability/test_attributes.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/unit/observability/test_projection_tracing.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/unit/observability/test_tracing.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/unit/snapshots/__init__.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/unit/snapshots/test_in_memory_snapshot_store.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/unit/snapshots/test_postgresql_snapshot_store.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/unit/snapshots/test_snapshot.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/unit/snapshots/test_snapshot_exceptions.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/unit/snapshots/test_snapshot_store_interface.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/unit/snapshots/test_snapshot_store_tracing.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/unit/snapshots/test_snapshots_module.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/unit/snapshots/test_sqlite_snapshot_store.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/unit/stores/__init__.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/unit/stores/test_memory_tracing.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/unit/stores/test_postgresql_tracing.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/unit/stores/test_sqlite_tracing.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/unit/test_additional_coverage.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/unit/test_aggregate_repository.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/unit/test_aggregate_root.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/unit/test_connection_helper.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/unit/test_domain_event.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/unit/test_event_bus.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/unit/test_event_registry.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/unit/test_exceptions.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/unit/test_fixtures.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/unit/test_in_memory_event_store.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/unit/test_json_encoder.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/unit/test_kafka_event_bus.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/unit/test_projection_base.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/unit/test_projection_coordinator.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/unit/test_projection_decorators.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/unit/test_projection_protocols.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/unit/test_protocols.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/unit/test_rabbitmq_exports.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/unit/test_redis_event_bus.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/unit/test_redis_event_bus_tracing.py +0 -0
- {eventsource_py-0.2.0 → eventsource_py-0.3.0}/tests/unit/test_timestamp_types.py +0 -0
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [0.3.0] - 2025-12-12
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **ReadModel Persistence Tooling** - Standardized read model persistence infrastructure (`eventsource.readmodels`)
|
|
15
|
+
- **Phase 1 - Core Components**:
|
|
16
|
+
- `ReadModel` base class with standard fields (id, timestamps, version, deleted_at)
|
|
17
|
+
- `ReadModelRepository` protocol with 13 methods for CRUD, querying, and lifecycle management
|
|
18
|
+
- `Query` and `Filter` classes for flexible, type-safe querying with operators (eq, ne, lt, gt, le, ge, in_, contains, startswith)
|
|
19
|
+
- `InMemoryReadModelRepository` implementation for testing and development
|
|
20
|
+
- **Phase 2 - SQL Backends**:
|
|
21
|
+
- `PostgreSQLReadModelRepository` with full async support via asyncpg
|
|
22
|
+
- `SQLiteReadModelRepository` with async support via aiosqlite
|
|
23
|
+
- Schema generation utilities (`generate_postgresql_schema()`, `generate_sqlite_schema()`) for automatic table creation from ReadModel classes
|
|
24
|
+
- **Phase 3 - Projection Integration**:
|
|
25
|
+
- `ReadModelProjection` base class integrating with `DatabaseProjection`
|
|
26
|
+
- `HandlerRegistry` integration with `@handles` decorator for event-driven updates
|
|
27
|
+
- Automatic repository injection into event handlers
|
|
28
|
+
- **Phase 4 - Enhanced Features**:
|
|
29
|
+
- Soft delete support with `get_deleted()` and `find_deleted()` methods
|
|
30
|
+
- Optimistic locking via `save_with_version_check()` for concurrent update safety
|
|
31
|
+
- `OptimisticLockError` and `ReadModelNotFoundError` exceptions
|
|
32
|
+
- Public exports from `eventsource.readmodels`: `ReadModel`, `ReadModelRepository`, `ReadModelProjection`, `Query`, `Filter`, `InMemoryReadModelRepository`, `PostgreSQLReadModelRepository`, `SQLiteReadModelRepository`
|
|
33
|
+
- New observability attributes: `ATTR_READ_MODEL_TYPE`, `ATTR_READ_MODEL_ID`
|
|
34
|
+
- **Multi-Tenant Live Migration** - Zero-downtime tenant migration between event stores (`eventsource.migration`)
|
|
35
|
+
- `MigrationCoordinator` orchestrating full migration lifecycle with pause/resume/abort controls
|
|
36
|
+
- `BulkCopier` for streaming historical event migration with checkpointing and configurable batch sizes
|
|
37
|
+
- `DualWriteInterceptor` for simultaneous writes to source and target stores during migration
|
|
38
|
+
- `CutoverManager` for sub-100ms atomic tenant routing switch with rollback capability
|
|
39
|
+
- `ConsistencyVerifier` for data integrity validation with COUNT, HASH, and FULL verification modes
|
|
40
|
+
- `SubscriptionMigrator` for checkpoint position translation between stores
|
|
41
|
+
- `TenantStoreRouter` for tenant-aware read/write routing during and after migration
|
|
42
|
+
- `WritePauseManager` for coordinated write pausing during cutover
|
|
43
|
+
- `SyncLagTracker` for monitoring replication lag between stores
|
|
44
|
+
- Real-time status streaming via `StatusStreamer` for migration monitoring
|
|
45
|
+
- Position mapping for checkpoint translation between source and target stores
|
|
46
|
+
- Comprehensive error classification with retry policies and circuit breaker pattern
|
|
47
|
+
- Audit logging for all migration operations
|
|
48
|
+
- OpenTelemetry metrics integration (`eventsource.migration.metrics`)
|
|
49
|
+
- **PostgreSQL Advisory Locks** - Distributed locking for migration coordination (`eventsource.locks`)
|
|
50
|
+
- `PostgreSQLAdvisoryLock` for session-level and transaction-level advisory locks
|
|
51
|
+
- Lock context managers for safe acquisition and release
|
|
52
|
+
- Lock timeout and retry configuration
|
|
53
|
+
- **Migration Exceptions** - Comprehensive exception hierarchy (`eventsource.migration.exceptions`)
|
|
54
|
+
- `MigrationError`, `MigrationStateError`, `MigrationNotFoundError`
|
|
55
|
+
- `BulkCopyError`, `DualWriteError`, `CutoverError`
|
|
56
|
+
- `ConsistencyError`, `RoutingError`, `LockError`
|
|
57
|
+
- Error classification with `ErrorCategory` and `ErrorSeverity` enums
|
|
58
|
+
- **Migration Documentation** - Comprehensive guides in `docs/migration/`:
|
|
59
|
+
- Architecture overview and component documentation
|
|
60
|
+
- Step-by-step migration guide
|
|
61
|
+
- API reference for all migration components
|
|
62
|
+
- Operational runbooks and troubleshooting guides
|
|
63
|
+
- Monitoring and alerting setup
|
|
64
|
+
|
|
65
|
+
- **Subscription Tracing** - OpenTelemetry tracing for all subscription components
|
|
66
|
+
- `SubscriptionManager` tracing for subscription lifecycle operations:
|
|
67
|
+
- `subscribe`, `unsubscribe`, `start_subscription`, `stop`, `stop_subscription`
|
|
68
|
+
- `pause_subscription`, `resume_subscription`
|
|
69
|
+
- `TransitionCoordinator` tracing for catch-up to live transitions:
|
|
70
|
+
- `execute` span with phase tracking (initial_catchup → live_subscribed → final_catchup → processing_buffer → live)
|
|
71
|
+
- Watermark and buffer size attributes
|
|
72
|
+
- `CatchUpRunner` tracing for historical event processing:
|
|
73
|
+
- `run_until_position` span with batch progress
|
|
74
|
+
- `deliver_event` span for individual event delivery
|
|
75
|
+
- `LiveRunner` tracing for real-time event processing:
|
|
76
|
+
- `start`, `stop`, `process_event` spans
|
|
77
|
+
- `process_buffer`, `process_pause_buffer` for transition buffers
|
|
78
|
+
- New subscription trace attributes in `eventsource.observability.attributes`:
|
|
79
|
+
- `ATTR_SUBSCRIPTION_NAME`, `ATTR_SUBSCRIPTION_STATE`, `ATTR_SUBSCRIPTION_PHASE`
|
|
80
|
+
- `ATTR_FROM_POSITION`, `ATTR_TO_POSITION`, `ATTR_BATCH_SIZE`
|
|
81
|
+
- `ATTR_BUFFER_SIZE`, `ATTR_EVENTS_PROCESSED`, `ATTR_EVENTS_SKIPPED`, `ATTR_WATERMARK`
|
|
82
|
+
- All components support `enable_tracing` parameter (default: `True`)
|
|
83
|
+
- Graceful degradation when OpenTelemetry is not installed
|
|
84
|
+
|
|
85
|
+
- **Subscription Manager** - New `eventsource.subscriptions` module for building event-driven projections with catch-up subscriptions and live event streaming
|
|
86
|
+
- `SubscriptionManager` class for coordinating subscriptions with unified lifecycle management
|
|
87
|
+
- Automatic catch-up from event store historical data
|
|
88
|
+
- Seamless transition to live event streaming via event bus
|
|
89
|
+
- Multiple subscriber support with concurrent processing
|
|
90
|
+
- Graceful shutdown with SIGTERM/SIGINT signal handling (`run_until_shutdown()`)
|
|
91
|
+
- Pause/resume functionality for individual subscriptions
|
|
92
|
+
- `Subscription` class with state machine for subscription lifecycle (idle → starting → catching_up → live → pausing → paused → resuming → stopping → stopped → failed)
|
|
93
|
+
- `SubscriptionConfig` for configurable subscription behavior:
|
|
94
|
+
- `batch_size`: Events per batch during catch-up (default: 100)
|
|
95
|
+
- `checkpoint_interval`: Events between checkpoints (default: 100)
|
|
96
|
+
- `checkpoint_strategy`: "batch" or "interval" checkpointing
|
|
97
|
+
- `start_from`: Start position ("beginning", "end", or specific position)
|
|
98
|
+
- `filter_event_types`: Optional event type filtering
|
|
99
|
+
- Subscriber protocols and base classes:
|
|
100
|
+
- `Subscriber` and `SyncSubscriber` protocols for event handlers
|
|
101
|
+
- `BatchSubscriber` protocol for batch event processing
|
|
102
|
+
- `BaseSubscriber`, `BatchAwareSubscriber`, and `FilteringSubscriber` base classes
|
|
103
|
+
- Catch-up and live runner implementations:
|
|
104
|
+
- `CatchupRunner` for reading historical events from event store with batching
|
|
105
|
+
- `LiveRunner` for streaming real-time events from event bus
|
|
106
|
+
- `TransitionCoordinator` for seamless handoff between modes
|
|
107
|
+
- Comprehensive error handling (`eventsource.subscriptions.error_handling`):
|
|
108
|
+
- `SubscriptionErrorHandler` with configurable retry policies
|
|
109
|
+
- `ErrorSeverity` levels: low, medium, high, critical
|
|
110
|
+
- `ErrorCategory` classification: event_processing, checkpoint, transition, infrastructure
|
|
111
|
+
- Error callbacks: `on_error()` and `on_critical_error()` hooks
|
|
112
|
+
- Circuit breaker pattern for failing subscriptions
|
|
113
|
+
- Retry system (`eventsource.subscriptions.retry`):
|
|
114
|
+
- Configurable retry with exponential backoff
|
|
115
|
+
- Jitter support for distributed systems
|
|
116
|
+
- Max retries and timeout limits
|
|
117
|
+
- Health monitoring (`eventsource.subscriptions.health`):
|
|
118
|
+
- `ManagerHealthChecker` for overall system health
|
|
119
|
+
- `SubscriptionHealthChecker` for per-subscription health
|
|
120
|
+
- Kubernetes-compatible liveness/readiness probes
|
|
121
|
+
- `HealthStatus`, `LivenessStatus`, `ReadinessStatus` enums
|
|
122
|
+
- Configurable health check thresholds
|
|
123
|
+
- Metrics collection (`eventsource.subscriptions.metrics`):
|
|
124
|
+
- Events processed, errors, lag, and processing duration metrics
|
|
125
|
+
- Per-subscription and aggregate statistics
|
|
126
|
+
- Flow control (`eventsource.subscriptions.flow_control`):
|
|
127
|
+
- Backpressure handling for slow consumers
|
|
128
|
+
- Rate limiting support
|
|
129
|
+
- Graceful shutdown (`eventsource.subscriptions.shutdown`):
|
|
130
|
+
- `ShutdownCoordinator` with phased shutdown sequence
|
|
131
|
+
- Configurable shutdown timeout
|
|
132
|
+
- In-flight event completion before shutdown
|
|
133
|
+
- `FlowController.wait_for_drain()` for tracking in-flight events during shutdown
|
|
134
|
+
- `ShutdownReason` enum for tracking shutdown triggers (SIGNAL_SIGTERM, SIGNAL_SIGINT, PROGRAMMATIC, HEALTH_CHECK, TIMEOUT, DOUBLE_SIGNAL)
|
|
135
|
+
- Pre-shutdown hooks (`on_pre_shutdown()`) for cleanup before shutdown (e.g., load balancer deregistration)
|
|
136
|
+
- Post-shutdown hooks (`on_post_shutdown()`) for actions after shutdown completes
|
|
137
|
+
- Shutdown deadline support (`set_shutdown_deadline()`) for Kubernetes `terminationGracePeriodSeconds` compliance
|
|
138
|
+
- Periodic checkpoint saves during drain phase (`checkpoint_interval` parameter)
|
|
139
|
+
- Shutdown metrics with OpenTelemetry integration (`ShutdownMetricsSnapshot`)
|
|
140
|
+
- Multi-instance coordination (`eventsource.subscriptions.coordination`):
|
|
141
|
+
- `LeaderElector` protocol for distributed leadership election
|
|
142
|
+
- `LeaderElectorWithLease` extended protocol for lease-based leadership
|
|
143
|
+
- `InMemoryLeaderElector` implementation for single-instance and testing scenarios
|
|
144
|
+
- `WorkRedistributionCoordinator` for coordinating work handoff during shutdown
|
|
145
|
+
- `ShutdownNotification` and `HeartbeatMessage` for peer-to-peer coordination
|
|
146
|
+
- Support for graceful work redistribution when instances shut down
|
|
147
|
+
- Event filtering (`eventsource.subscriptions.filtering`):
|
|
148
|
+
- Filter events by type, aggregate, or custom predicates
|
|
149
|
+
- Global position support in event stores:
|
|
150
|
+
- `PostgreSQLEventStore.subscribe_all_from_position()` for ordered event streaming
|
|
151
|
+
- `SQLiteEventStore.subscribe_all_from_position()` for ordered event streaming
|
|
152
|
+
- `global_position` field in stored events for total ordering
|
|
153
|
+
- Database migrations for `checkpoints` table with position tracking
|
|
154
|
+
- Comprehensive documentation: API reference, user guide, migration guide, and examples
|
|
155
|
+
- Exception hierarchy: `SubscriptionError`, `SubscriptionConfigError`, `SubscriptionStateError`, `SubscriptionAlreadyExistsError`, `CheckpointNotFoundError`
|
|
156
|
+
- **TypeConverter Extraction** - Refactored serialization logic from event stores into a dedicated component
|
|
157
|
+
- New `TypeConverter` protocol defining the contract for type conversion during event deserialization
|
|
158
|
+
- `DefaultTypeConverter` implementation with configurable UUID and datetime field detection
|
|
159
|
+
- `DEFAULT_UUID_FIELDS` and `DEFAULT_STRING_ID_FIELDS` constants for common field patterns
|
|
160
|
+
- `DefaultTypeConverter.strict()` factory method for explicit-only UUID field configuration
|
|
161
|
+
- SQLiteEventStore now has full configuration parity with PostgreSQLEventStore:
|
|
162
|
+
- Added `uuid_fields`, `string_id_fields`, and `auto_detect_uuid` constructor parameters
|
|
163
|
+
- Added `with_strict_uuid_detection()` factory method
|
|
164
|
+
- Public exports from `eventsource.stores`: `TypeConverter`, `DefaultTypeConverter`, `DEFAULT_UUID_FIELDS`, `DEFAULT_STRING_ID_FIELDS`
|
|
165
|
+
- 37 unit tests for comprehensive TypeConverter coverage
|
|
166
|
+
|
|
167
|
+
### Changed
|
|
168
|
+
|
|
169
|
+
- Removed ~120 lines of duplicate serialization code from PostgreSQL and SQLite event stores by extracting to shared `TypeConverter`
|
|
170
|
+
|
|
171
|
+
### Fixed
|
|
172
|
+
|
|
173
|
+
- **SQLiteOutboxRepository**: `get_pending_events()` now returns `list[OutboxEntry]` instead of `list[dict]`, matching the protocol specification
|
|
174
|
+
- **SQLiteOutboxRepository**: `add_event()` now properly stores and returns a UUID as the outbox ID, matching PostgreSQL behavior
|
|
175
|
+
- **SQLiteDLQRepository**: `get_failed_events()` now properly parses timestamp fields (`first_failed_at`, `last_failed_at`) from ISO 8601 strings to `datetime` objects
|
|
176
|
+
- **SQLiteDLQRepository**: `get_failed_event_by_id()` now properly parses timestamp fields (`first_failed_at`, `last_failed_at`, `resolved_at`) to `datetime` objects
|
|
177
|
+
- **SQLite schema**: Event outbox table now uses `TEXT PRIMARY KEY` for the `id` column (UUID as string) instead of `INTEGER PRIMARY KEY AUTOINCREMENT` to match PostgreSQL schema
|
|
178
|
+
|
|
179
|
+
### Breaking Changes (Internal)
|
|
180
|
+
|
|
181
|
+
- Internal methods `_is_uuid_field()` and `_convert_types()` on event stores have been removed
|
|
182
|
+
- Users who were calling these internal methods directly should migrate to `store._type_converter.is_uuid_field()` and `store._type_converter.convert_types()`
|
|
183
|
+
|
|
184
|
+
### Documentation
|
|
185
|
+
|
|
186
|
+
- Added subscription manager user guide (`docs/guides/subscriptions.md`) covering:
|
|
187
|
+
- Getting started with catch-up and live subscriptions
|
|
188
|
+
- Basic usage patterns and configuration
|
|
189
|
+
- Resilience patterns and error handling
|
|
190
|
+
- Advanced patterns for production deployments
|
|
191
|
+
- Troubleshooting guide
|
|
192
|
+
- Added subscription API reference (`docs/api/subscriptions.md`) with complete class and method documentation
|
|
193
|
+
- Added subscription migration guide (`docs/guides/subscription-migration.md`) for migrating from manual projection processing
|
|
194
|
+
- Added subscription examples (`examples/subscriptions/`) with:
|
|
195
|
+
- Basic projection example
|
|
196
|
+
- Multi-subscriber example
|
|
197
|
+
- Resilient projection with error handling
|
|
198
|
+
- **Updated all projection examples to use SubscriptionManager pattern**:
|
|
199
|
+
- `examples/projection_example.py` now demonstrates SubscriptionManager with catch-up, live subscriptions, and checkpoint tracking
|
|
200
|
+
- `docs/getting-started.md` updated with SubscriptionManager as the recommended approach
|
|
201
|
+
- `docs/examples/projections.md` now recommends SubscriptionManager over direct `event_bus.subscribe_all()`
|
|
202
|
+
- `docs/examples/sqlite-usage.md` integration tests updated to use SubscriptionManager
|
|
203
|
+
- Added comparison table showing benefits of SubscriptionManager vs direct EventBus subscription
|
|
204
|
+
- Added Kubernetes deployment guide (`docs/guides/kubernetes-deployment.md`) covering:
|
|
205
|
+
- Pod lifecycle integration and graceful shutdown
|
|
206
|
+
- Health probe configuration (liveness, readiness, startup)
|
|
207
|
+
- `terminationGracePeriodSeconds` configuration with shutdown deadline
|
|
208
|
+
- Example Deployment, Service, and PodDisruptionBudget manifests
|
|
209
|
+
- Spot instance and preemptible VM considerations (AWS, GCP, Azure)
|
|
210
|
+
- Shutdown metrics and observability
|
|
211
|
+
- Troubleshooting guide for common Kubernetes issues
|
|
212
|
+
|
|
213
|
+
### Tests
|
|
214
|
+
|
|
215
|
+
- Added comprehensive ReadModel persistence test suite:
|
|
216
|
+
- Unit tests for all ReadModel components (`tests/unit/readmodels/`)
|
|
217
|
+
- Base class and field validation tests
|
|
218
|
+
- Query and Filter class tests
|
|
219
|
+
- Repository protocol compliance tests
|
|
220
|
+
- In-memory repository tests
|
|
221
|
+
- PostgreSQL and SQLite repository tests
|
|
222
|
+
- Schema generation tests
|
|
223
|
+
- Projection integration tests
|
|
224
|
+
- Handler registry integration tests
|
|
225
|
+
- Integration tests (`tests/integration/readmodels/`)
|
|
226
|
+
- Repository CRUD operations across all backends
|
|
227
|
+
- Projection event handling flows
|
|
228
|
+
- Enhanced features (soft delete, optimistic locking)
|
|
229
|
+
- Added comprehensive migration test suite (~950 new tests):
|
|
230
|
+
- Unit tests for all migration components (`tests/unit/migration/`)
|
|
231
|
+
- Integration tests for PostgreSQL locks and migration schema
|
|
232
|
+
- Chaos tests for failure scenarios and recovery
|
|
233
|
+
- Load testing benchmarks for performance validation
|
|
234
|
+
- Phase integration tests for bulk copy, dual write, and cutover
|
|
235
|
+
- Added comprehensive subscription manager test suite:
|
|
236
|
+
- Unit tests for all subscription components (`tests/unit/subscriptions/`)
|
|
237
|
+
- Integration tests for catch-up, live, and transition flows (`tests/integration/subscriptions/`)
|
|
238
|
+
- Resilience tests for error handling, retries, and recovery
|
|
239
|
+
- Health check and metrics tests
|
|
240
|
+
- Pause/resume functionality tests
|
|
241
|
+
- Backpressure and flow control tests
|
|
242
|
+
- Drain functionality tests (`test_drain.py`) for shutdown coordination
|
|
243
|
+
- Coordination protocol tests (`test_coordination.py`) for leader election and work redistribution
|
|
244
|
+
- Shutdown tests for pre/post hooks, deadline, metrics, and reason tracking
|
|
245
|
+
|
|
246
|
+
## [0.2.0] - 2025-12-08
|
|
247
|
+
|
|
248
|
+
### Added
|
|
249
|
+
|
|
250
|
+
#### Observability & Telemetry
|
|
251
|
+
|
|
252
|
+
- **Observability Module** (`eventsource.observability`) - Reusable OpenTelemetry utilities
|
|
253
|
+
- `OTEL_AVAILABLE` constant for checking OpenTelemetry availability
|
|
254
|
+
- `get_tracer()` and `should_trace()` helper functions
|
|
255
|
+
- `@traced` decorator for method-level tracing
|
|
256
|
+
- `TracingMixin` class for consistent tracing across components
|
|
257
|
+
- **Kafka Event Bus Metrics** - Comprehensive OpenTelemetry metrics
|
|
258
|
+
- Counters: `messages.published`, `messages.consumed`, `handler.invocations`, `handler.errors`, `messages.dlq`, `connection.errors`, `reconnections`, `rebalances`, `publish.errors`
|
|
259
|
+
- Histograms: `publish.duration`, `consume.duration`, `handler.duration`, `batch.size`
|
|
260
|
+
- Gauges: `connections.active`, `consumer.lag` (per partition)
|
|
261
|
+
- New `KafkaEventBusMetrics` class with `enable_metrics` config option
|
|
262
|
+
- Less than 5% performance overhead
|
|
263
|
+
- **SQLiteEventStore Tracing** - `enable_tracing` parameter for `append_events` and `get_events` operations
|
|
264
|
+
- **InMemoryEventBus Tracing** - `enable_tracing` parameter for event dispatch and handler execution
|
|
265
|
+
|
|
266
|
+
#### Aggregate Snapshotting
|
|
267
|
+
|
|
268
|
+
- `Snapshot` dataclass for point-in-time aggregate state capture
|
|
269
|
+
- `SnapshotStore` interface with `InMemorySnapshotStore`, `PostgreSQLSnapshotStore`, and `SQLiteSnapshotStore` implementations
|
|
270
|
+
- `AggregateRepository` snapshot support: `snapshot_store`, `snapshot_threshold`, and `snapshot_mode` parameters
|
|
271
|
+
- `AggregateRoot.schema_version` for snapshot schema evolution with automatic invalidation
|
|
272
|
+
- `create_snapshot()` and `await_pending_snapshots()` methods
|
|
273
|
+
- Snapshot exceptions: `SnapshotError`, `SnapshotDeserializationError`, `SnapshotSchemaVersionError`, `SnapshotNotFoundError`
|
|
274
|
+
- Database migrations for `snapshots` table (PostgreSQL and SQLite)
|
|
275
|
+
|
|
276
|
+
#### Event Handling & Validation
|
|
277
|
+
|
|
278
|
+
- `EventVersionError` exception and configurable version validation via `AggregateRoot.validate_versions`
|
|
279
|
+
- `UnhandledEventError` exception with configurable handling via `unregistered_event_handling` attribute ("ignore", "warn", "error")
|
|
280
|
+
- `FlexibleEventHandler` and `FlexibleEventSubscriber` protocols for sync/async handler signatures
|
|
281
|
+
- Consolidated `eventsource.protocols` module as canonical location for protocol definitions
|
|
282
|
+
|
|
283
|
+
#### Database & Repository
|
|
284
|
+
|
|
285
|
+
- `DatabaseProjection` class for projections requiring raw database connection access
|
|
286
|
+
- `execute_with_connection` helper for consistent connection handling
|
|
287
|
+
- Configurable UUID field detection in `PostgreSQLEventStore` via `uuid_fields`, `string_id_fields`, and `auto_detect_uuid` parameters
|
|
288
|
+
- `PostgreSQLEventStore.with_strict_uuid_detection()` class method
|
|
289
|
+
|
|
290
|
+
#### Developer Experience
|
|
291
|
+
|
|
292
|
+
- Pre-commit hooks with ruff, mypy, and bandit
|
|
293
|
+
- GitHub Actions workflow for performance benchmarks with baseline tracking and PR comparison
|
|
294
|
+
- Shared test fixtures module (`tests/fixtures/`) with reusable components
|
|
295
|
+
|
|
296
|
+
### Changed
|
|
297
|
+
|
|
298
|
+
- Improved type annotations for better mypy compatibility
|
|
299
|
+
- Consolidated `@handles` decorator to `eventsource.projections.decorators` (old location deprecated)
|
|
300
|
+
- Consolidated protocol definitions to `eventsource.protocols` (old locations deprecated)
|
|
301
|
+
- Repository methods `get_pending_events`, `get_failed_events`, `get_failed_event_by_id` now return typed dataclasses (`OutboxEntry`, `DLQEntry`) instead of dicts
|
|
302
|
+
- Unified `get_events_by_type()` timestamp parameters to use `datetime` instead of `float`
|
|
303
|
+
- Refactored repositories to use `execute_with_connection` helper
|
|
304
|
+
- In-memory repositories now use `asyncio.Lock` for proper async concurrency
|
|
305
|
+
|
|
306
|
+
### Removed
|
|
307
|
+
|
|
308
|
+
- `SyncEventStore` abstract class (use `asyncio.run()` for sync access; see ADR-0007)
|
|
309
|
+
|
|
310
|
+
### Fixed
|
|
311
|
+
|
|
312
|
+
- Broken documentation links in ADRs and guides
|
|
313
|
+
- Mypy type errors in projections, repositories, and event bus modules
|
|
314
|
+
- `DeclarativeProjection` connection handling for proper transaction sharing
|
|
315
|
+
|
|
316
|
+
## [0.1.3] - 2025-12-07
|
|
317
|
+
|
|
318
|
+
### Documentation
|
|
319
|
+
|
|
320
|
+
- Added documentation badge linking to GitHub Pages
|
|
321
|
+
- Updated all documentation URLs to point to https://tyevans.github.io/eventsource-py
|
|
322
|
+
- Fixed mkdocs.yml site configuration with correct repository URLs
|
|
323
|
+
- Simplified README documentation section with links to hosted docs
|
|
324
|
+
|
|
325
|
+
## [0.1.2] - 2025-12-07
|
|
326
|
+
|
|
327
|
+
### Fixed
|
|
328
|
+
|
|
329
|
+
- Fixed release workflow version validation
|
|
330
|
+
|
|
331
|
+
## [0.1.1] - 2025-12-07
|
|
332
|
+
|
|
333
|
+
### Fixed
|
|
334
|
+
|
|
335
|
+
- Release infrastructure corrections
|
|
336
|
+
|
|
337
|
+
## [0.1.0] - 2025-12-07
|
|
338
|
+
|
|
339
|
+
### Added
|
|
340
|
+
|
|
341
|
+
- Initial release of eventsource-py library
|
|
342
|
+
- Event Store with PostgreSQL, SQLite, and In-Memory backends
|
|
343
|
+
- Domain Events with Pydantic validation
|
|
344
|
+
- Aggregate base class with optimistic concurrency control
|
|
345
|
+
- Projection system for building read models with checkpoint tracking
|
|
346
|
+
- Dead Letter Queue (DLQ) for failed event handling
|
|
347
|
+
- Snapshot support for aggregate state caching
|
|
348
|
+
- Multi-tenant support with tenant isolation
|
|
349
|
+
- Async-first API design throughout
|
|
350
|
+
- Comprehensive type hints and mypy compatibility
|
|
351
|
+
- Event registry for type-safe event deserialization
|
|
352
|
+
- Event Bus with In-Memory and Redis Streams backends
|
|
353
|
+
- Transactional Outbox pattern implementation
|
|
354
|
+
- `DatabaseProjection` class for projections requiring raw database connection access
|
|
355
|
+
- Pre-commit hooks configuration with ruff, mypy, and bandit
|
|
356
|
+
|
|
357
|
+
### Infrastructure
|
|
358
|
+
|
|
359
|
+
- PostgreSQL backend with connection pooling (asyncpg)
|
|
360
|
+
- SQLite backend for lightweight deployments, development, and testing
|
|
361
|
+
- Redis Streams backend for distributed event bus
|
|
362
|
+
- In-Memory backends for testing and development
|
|
363
|
+
- Automatic schema creation and migrations
|
|
364
|
+
- GitHub Actions CI/CD pipeline
|
|
365
|
+
|
|
366
|
+
[Unreleased]: https://github.com/tyevans/eventsource-py/compare/v0.3.0...HEAD
|
|
367
|
+
[0.3.0]: https://github.com/tyevans/eventsource-py/compare/v0.2.0...v0.3.0
|
|
368
|
+
[0.2.0]: https://github.com/tyevans/eventsource-py/compare/v0.1.3...v0.2.0
|
|
369
|
+
[0.1.3]: https://github.com/tyevans/eventsource-py/compare/v0.1.2...v0.1.3
|
|
370
|
+
[0.1.2]: https://github.com/tyevans/eventsource-py/compare/v0.1.1...v0.1.2
|
|
371
|
+
[0.1.1]: https://github.com/tyevans/eventsource-py/compare/v0.1.0...v0.1.1
|
|
372
|
+
[0.1.0]: https://github.com/tyevans/eventsource-py/releases/tag/v0.1.0
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: eventsource-py
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: Production-ready event sourcing library for Python
|
|
5
|
+
Project-URL: Homepage, https://github.com/tyevans/eventsource-py
|
|
6
|
+
Project-URL: Documentation, https://tyevans.github.io/eventsource-py
|
|
7
|
+
Project-URL: Repository, https://github.com/tyevans/eventsource-py
|
|
8
|
+
Project-URL: Changelog, https://github.com/tyevans/eventsource-py/blob/main/CHANGELOG.md
|
|
9
|
+
Author-email: Ty Evans <tyevans@gmail.com>
|
|
10
|
+
License: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: cqrs,ddd,domain-driven-design,event-sourcing,events
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
21
|
+
Classifier: Typing :: Typed
|
|
22
|
+
Requires-Python: >=3.11
|
|
23
|
+
Requires-Dist: pydantic<3.0,>=2.0
|
|
24
|
+
Requires-Dist: redis>=5.0
|
|
25
|
+
Requires-Dist: sqlalchemy<3.0,>=2.0
|
|
26
|
+
Provides-Extra: all
|
|
27
|
+
Requires-Dist: aio-pika>=9.0.0; extra == 'all'
|
|
28
|
+
Requires-Dist: aiokafka<1.0.0,>=0.9.0; extra == 'all'
|
|
29
|
+
Requires-Dist: aiosqlite<1.0,>=0.19.0; extra == 'all'
|
|
30
|
+
Requires-Dist: asyncpg<1.0,>=0.27.0; extra == 'all'
|
|
31
|
+
Requires-Dist: opentelemetry-api<2.0,>=1.0; extra == 'all'
|
|
32
|
+
Requires-Dist: opentelemetry-sdk<2.0,>=1.0; extra == 'all'
|
|
33
|
+
Requires-Dist: redis<6.0,>=5.0; extra == 'all'
|
|
34
|
+
Provides-Extra: all-backends
|
|
35
|
+
Requires-Dist: aiosqlite<1.0,>=0.19.0; extra == 'all-backends'
|
|
36
|
+
Requires-Dist: asyncpg<1.0,>=0.27.0; extra == 'all-backends'
|
|
37
|
+
Provides-Extra: benchmark
|
|
38
|
+
Requires-Dist: pytest-benchmark>=4.0.0; extra == 'benchmark'
|
|
39
|
+
Provides-Extra: dev
|
|
40
|
+
Requires-Dist: mypy>=1.8; extra == 'dev'
|
|
41
|
+
Requires-Dist: pre-commit>=4.0; extra == 'dev'
|
|
42
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
|
|
43
|
+
Requires-Dist: pytest-benchmark>=4.0.0; extra == 'dev'
|
|
44
|
+
Requires-Dist: pytest-cov>=4.0; extra == 'dev'
|
|
45
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
46
|
+
Requires-Dist: ruff>=0.14.8; extra == 'dev'
|
|
47
|
+
Requires-Dist: testcontainers>=4.0; extra == 'dev'
|
|
48
|
+
Provides-Extra: docs
|
|
49
|
+
Requires-Dist: mkdocs-material>=9.5; extra == 'docs'
|
|
50
|
+
Requires-Dist: mkdocs>=1.5; extra == 'docs'
|
|
51
|
+
Requires-Dist: mkdocstrings[python]>=0.24; extra == 'docs'
|
|
52
|
+
Requires-Dist: pymdown-extensions>=10.0; extra == 'docs'
|
|
53
|
+
Provides-Extra: kafka
|
|
54
|
+
Requires-Dist: aiokafka<1.0.0,>=0.9.0; extra == 'kafka'
|
|
55
|
+
Provides-Extra: kafka-schema-registry
|
|
56
|
+
Requires-Dist: aiokafka<1.0.0,>=0.9.0; extra == 'kafka-schema-registry'
|
|
57
|
+
Requires-Dist: confluent-kafka<3.0.0,>=2.0.0; extra == 'kafka-schema-registry'
|
|
58
|
+
Provides-Extra: postgresql
|
|
59
|
+
Requires-Dist: asyncpg<1.0,>=0.27.0; extra == 'postgresql'
|
|
60
|
+
Provides-Extra: rabbitmq
|
|
61
|
+
Requires-Dist: aio-pika>=9.0.0; extra == 'rabbitmq'
|
|
62
|
+
Provides-Extra: redis
|
|
63
|
+
Requires-Dist: redis<6.0,>=5.0; extra == 'redis'
|
|
64
|
+
Provides-Extra: sqlite
|
|
65
|
+
Requires-Dist: aiosqlite<1.0,>=0.19.0; extra == 'sqlite'
|
|
66
|
+
Provides-Extra: telemetry
|
|
67
|
+
Requires-Dist: opentelemetry-api<2.0,>=1.0; extra == 'telemetry'
|
|
68
|
+
Requires-Dist: opentelemetry-sdk<2.0,>=1.0; extra == 'telemetry'
|
|
69
|
+
Description-Content-Type: text/markdown
|
|
70
|
+
|
|
71
|
+
# eventsource-py
|
|
72
|
+
|
|
73
|
+
[](https://pypi.org/project/eventsource-py/)
|
|
74
|
+
[](https://www.python.org/downloads/)
|
|
75
|
+
[](https://github.com/tyevans/eventsource-py/actions)
|
|
76
|
+
[](https://opensource.org/licenses/MIT)
|
|
77
|
+
|
|
78
|
+
**Stop losing data. Start capturing history.**
|
|
79
|
+
|
|
80
|
+
Traditional databases overwrite state on every update. Event sourcing captures *what happened* as a sequence of immutable events, giving you:
|
|
81
|
+
|
|
82
|
+
- **Complete audit trail** - Know exactly what changed, when, and why
|
|
83
|
+
- **Time travel** - Reconstruct state at any point in history
|
|
84
|
+
- **Multiple views** - Build different read models from the same events
|
|
85
|
+
- **Reliable debugging** - Replay events to reproduce any bug
|
|
86
|
+
|
|
87
|
+
eventsource-py makes this practical for Python applications with a clean, async-first API.
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
pip install eventsource-py
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Quick Start
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
import asyncio
|
|
97
|
+
from uuid import UUID, uuid4
|
|
98
|
+
from pydantic import BaseModel
|
|
99
|
+
from eventsource import (
|
|
100
|
+
DomainEvent, register_event, AggregateRoot, AggregateRepository,
|
|
101
|
+
InMemoryEventStore, InMemoryEventBus, InMemoryCheckpointRepository,
|
|
102
|
+
)
|
|
103
|
+
from eventsource.subscriptions import SubscriptionManager, SubscriptionConfig
|
|
104
|
+
|
|
105
|
+
# 1. Define events - immutable facts that capture what happened
|
|
106
|
+
@register_event
|
|
107
|
+
class OrderPlaced(DomainEvent):
|
|
108
|
+
event_type: str = "OrderPlaced"
|
|
109
|
+
aggregate_type: str = "Order"
|
|
110
|
+
customer_id: UUID
|
|
111
|
+
total: float
|
|
112
|
+
|
|
113
|
+
@register_event
|
|
114
|
+
class OrderShipped(DomainEvent):
|
|
115
|
+
event_type: str = "OrderShipped"
|
|
116
|
+
aggregate_type: str = "Order"
|
|
117
|
+
tracking_number: str
|
|
118
|
+
|
|
119
|
+
# 2. Define aggregate state and business logic
|
|
120
|
+
class OrderState(BaseModel):
|
|
121
|
+
order_id: UUID
|
|
122
|
+
customer_id: UUID | None = None
|
|
123
|
+
total: float = 0.0
|
|
124
|
+
status: str = "draft"
|
|
125
|
+
|
|
126
|
+
class Order(AggregateRoot[OrderState]):
|
|
127
|
+
aggregate_type = "Order"
|
|
128
|
+
|
|
129
|
+
def _get_initial_state(self) -> OrderState:
|
|
130
|
+
return OrderState(order_id=self.aggregate_id)
|
|
131
|
+
|
|
132
|
+
def _apply(self, event: DomainEvent) -> None:
|
|
133
|
+
match event:
|
|
134
|
+
case OrderPlaced():
|
|
135
|
+
self._state = OrderState(
|
|
136
|
+
order_id=self.aggregate_id,
|
|
137
|
+
customer_id=event.customer_id,
|
|
138
|
+
total=event.total,
|
|
139
|
+
status="placed",
|
|
140
|
+
)
|
|
141
|
+
case OrderShipped():
|
|
142
|
+
self._state = self._state.model_copy(update={"status": "shipped"})
|
|
143
|
+
|
|
144
|
+
def place(self, customer_id: UUID, total: float) -> None:
|
|
145
|
+
if self.version > 0:
|
|
146
|
+
raise ValueError("Order already placed")
|
|
147
|
+
self.apply_event(OrderPlaced(
|
|
148
|
+
aggregate_id=self.aggregate_id,
|
|
149
|
+
customer_id=customer_id,
|
|
150
|
+
total=total,
|
|
151
|
+
aggregate_version=self.get_next_version(),
|
|
152
|
+
))
|
|
153
|
+
|
|
154
|
+
def ship(self, tracking_number: str) -> None:
|
|
155
|
+
if self.state.status != "placed":
|
|
156
|
+
raise ValueError("Order must be placed before shipping")
|
|
157
|
+
self.apply_event(OrderShipped(
|
|
158
|
+
aggregate_id=self.aggregate_id,
|
|
159
|
+
tracking_number=tracking_number,
|
|
160
|
+
aggregate_version=self.get_next_version(),
|
|
161
|
+
))
|
|
162
|
+
|
|
163
|
+
# 3. Define a projection - build read models from the event stream
|
|
164
|
+
class SalesReport:
|
|
165
|
+
"""Read model that tracks sales metrics from events."""
|
|
166
|
+
def __init__(self):
|
|
167
|
+
self.total_revenue = 0.0
|
|
168
|
+
self.orders_placed = 0
|
|
169
|
+
self.orders_shipped = 0
|
|
170
|
+
|
|
171
|
+
def subscribed_to(self) -> list[type[DomainEvent]]:
|
|
172
|
+
return [OrderPlaced, OrderShipped]
|
|
173
|
+
|
|
174
|
+
async def handle(self, event: DomainEvent) -> None:
|
|
175
|
+
match event:
|
|
176
|
+
case OrderPlaced():
|
|
177
|
+
self.total_revenue += event.total
|
|
178
|
+
self.orders_placed += 1
|
|
179
|
+
case OrderShipped():
|
|
180
|
+
self.orders_shipped += 1
|
|
181
|
+
|
|
182
|
+
# 4. Wire it together
|
|
183
|
+
async def main():
|
|
184
|
+
# Infrastructure
|
|
185
|
+
store = InMemoryEventStore()
|
|
186
|
+
bus = InMemoryEventBus()
|
|
187
|
+
repo = AggregateRepository(
|
|
188
|
+
event_store=store,
|
|
189
|
+
aggregate_factory=Order,
|
|
190
|
+
aggregate_type="Order",
|
|
191
|
+
event_publisher=bus, # Publishes events to the bus after saving
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
# Set up subscription manager with our projection
|
|
195
|
+
manager = SubscriptionManager(store, bus, InMemoryCheckpointRepository())
|
|
196
|
+
report = SalesReport()
|
|
197
|
+
await manager.subscribe(report, SubscriptionConfig(start_from="beginning"), name="SalesReport")
|
|
198
|
+
await manager.start()
|
|
199
|
+
|
|
200
|
+
# Create some orders
|
|
201
|
+
for i in range(3):
|
|
202
|
+
order = repo.create_new(uuid4())
|
|
203
|
+
order.place(customer_id=uuid4(), total=100.0 * (i + 1))
|
|
204
|
+
await repo.save(order)
|
|
205
|
+
|
|
206
|
+
if i == 0: # Ship the first order
|
|
207
|
+
order.ship(tracking_number="TRACK-001")
|
|
208
|
+
await repo.save(order)
|
|
209
|
+
|
|
210
|
+
await asyncio.sleep(0.1) # Let events propagate
|
|
211
|
+
|
|
212
|
+
# The projection built a read model from the event stream
|
|
213
|
+
print(f"Revenue: ${report.total_revenue}") # Revenue: $600.0
|
|
214
|
+
print(f"Orders placed: {report.orders_placed}") # Orders placed: 3
|
|
215
|
+
print(f"Orders shipped: {report.orders_shipped}") # Orders shipped: 1
|
|
216
|
+
|
|
217
|
+
# Events are the source of truth - reload aggregate from its event history
|
|
218
|
+
order = await repo.load(order.aggregate_id)
|
|
219
|
+
print(f"Order status: {order.state.status}") # Order status: shipped
|
|
220
|
+
print(f"Order version: {order.version}") # Order version: 2 (placed + shipped)
|
|
221
|
+
|
|
222
|
+
await manager.stop()
|
|
223
|
+
|
|
224
|
+
asyncio.run(main())
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
## Production Ready
|
|
228
|
+
|
|
229
|
+
Swap in production backends when you're ready to deploy:
|
|
230
|
+
|
|
231
|
+
| Component | Development | Production |
|
|
232
|
+
|-----------|-------------|------------|
|
|
233
|
+
| Event Store | `InMemoryEventStore` | `PostgreSQLEventStore`, `SQLiteEventStore` |
|
|
234
|
+
| Event Bus | `InMemoryEventBus` | `RedisEventBus`, `RabbitMQEventBus`, `KafkaEventBus` |
|
|
235
|
+
| Checkpoints | `InMemoryCheckpointRepository` | `PostgreSQLCheckpointRepository` |
|
|
236
|
+
|
|
237
|
+
```bash
|
|
238
|
+
# Add PostgreSQL + Redis for production
|
|
239
|
+
pip install eventsource-py[postgresql,redis]
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
<details>
|
|
243
|
+
<summary>All installation options</summary>
|
|
244
|
+
|
|
245
|
+
```bash
|
|
246
|
+
pip install eventsource-py[postgresql] # PostgreSQL event store
|
|
247
|
+
pip install eventsource-py[sqlite] # SQLite event store
|
|
248
|
+
pip install eventsource-py[redis] # Redis event bus
|
|
249
|
+
pip install eventsource-py[rabbitmq] # RabbitMQ event bus
|
|
250
|
+
pip install eventsource-py[kafka] # Kafka event bus
|
|
251
|
+
pip install eventsource-py[telemetry] # OpenTelemetry tracing
|
|
252
|
+
pip install eventsource-py[all] # Everything
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
</details>
|
|
256
|
+
|
|
257
|
+
## Features
|
|
258
|
+
|
|
259
|
+
- **Event Stores** - PostgreSQL, SQLite, In-Memory with optimistic concurrency
|
|
260
|
+
- **Event Bus** - Redis Streams, RabbitMQ, Kafka, In-Memory with consumer groups
|
|
261
|
+
- **Subscriptions** - Catch-up from history, live events, checkpointing, graceful shutdown
|
|
262
|
+
- **Projections** - Declarative handlers, retry logic, dead letter queues
|
|
263
|
+
- **Snapshots** - Optimize aggregate loading for long event streams
|
|
264
|
+
- **Multi-tenancy** - Built-in tenant isolation
|
|
265
|
+
- **Observability** - OpenTelemetry integration
|
|
266
|
+
|
|
267
|
+
## Documentation
|
|
268
|
+
|
|
269
|
+
**[Full Documentation](https://tyevans.github.io/eventsource-py)** - Guides, examples, and API reference
|
|
270
|
+
|
|
271
|
+
## License
|
|
272
|
+
|
|
273
|
+
MIT
|