pg_eventstore 2.0.0 → 3.0.0
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.
- checksums.yaml +4 -4
- data/.rubocop.yml +10 -1
- data/CHANGELOG.md +186 -20
- data/README.md +25 -15
- data/db/migrations/10_setup_pg_cron.rb +1 -23
- data/db/migrations/15_create_streams_global_index.sql +17 -0
- data/db/migrations/16_populate_streams_global_index.rb +150 -0
- data/db/migrations/17_create_events_global_index.sql +62 -0
- data/db/migrations/18_populate_events_global_index.rb +124 -0
- data/db/migrations/19_populate_events_global_index_p2.rb +25 -0
- data/db/migrations/20_migrate_subscriptions_current_position.sql +19 -0
- data/db/migrations/21_create_partitions_stats.sql +2 -0
- data/db/migrations/22_drop_streams_sql_view.sql +2 -0
- data/db/migrations/23_adjust_partitions_indexes.sql +5 -0
- data/db/migrations/24_drop_legacy_events_indexes.sql +3 -0
- data/db/migrations/25_add_parent_partitions_info_to_partitions.sql +16 -0
- data/db/migrations/26_change_events_stream_revision_type.rb +35 -0
- data/db/migrations/27_drop_events_horizon.sql +3 -0
- data/db/migrations/28_create_maintenance_tasks.sql +8 -0
- data/db/migrations/29_create_event_markers.sql +35 -0
- data/db/migrations/30_improve_partitions_search_in_admin_ui.rb +24 -0
- data/db/migrations/31_drop_events_id_default_value.sql +1 -0
- data/db/migrations/32_create_parittions_triggers.sql +101 -0
- data/docs/AGENTS.fragment.md +696 -0
- data/docs/admin_ui.md +3 -1
- data/docs/appending_events.md +110 -49
- data/docs/configuration.md +69 -36
- data/docs/event_tracing.md +55 -0
- data/docs/events_and_streams.md +54 -30
- data/docs/how_it_works.md +57 -16
- data/docs/linking_events.md +2 -1
- data/docs/maintenance.md +14 -5
- data/docs/multiple_commands.md +17 -8
- data/docs/reading_events.md +208 -43
- data/docs/reading_streams.md +50 -0
- data/docs/replication.md +99 -0
- data/docs/subscriptions.md +165 -35
- data/docs/writing_middleware.md +25 -8
- data/ext/pg_eventstore_ext/extconf.rb +5 -0
- data/ext/pg_eventstore_ext/pg_eventstore_ext.c +74 -0
- data/lib/pg_eventstore/async_runner.rb +63 -0
- data/lib/pg_eventstore/basic_config.rb +15 -0
- data/lib/pg_eventstore/chunks/chunk.rb +31 -0
- data/lib/pg_eventstore/chunks/read_api_events_index_chunk.rb +83 -0
- data/lib/pg_eventstore/chunks/replica_events_index_chunk.rb +35 -0
- data/lib/pg_eventstore/chunks/repository.rb +73 -0
- data/lib/pg_eventstore/chunks/subscription_checkpoint_chunk.rb +48 -0
- data/lib/pg_eventstore/chunks/subscription_events_index_chunk.rb +99 -0
- data/lib/pg_eventstore/chunks.rb +14 -0
- data/lib/pg_eventstore/client.rb +163 -50
- data/lib/pg_eventstore/commands/append.rb +62 -43
- data/lib/pg_eventstore/commands/delete_event.rb +7 -8
- data/lib/pg_eventstore/commands/delete_stream.rb +3 -3
- data/lib/pg_eventstore/commands/event_modifiers/prepare_link_event.rb +9 -7
- data/lib/pg_eventstore/commands/event_modifiers/prepare_regular_event.rb +12 -7
- data/lib/pg_eventstore/commands/link_to.rb +5 -5
- data/lib/pg_eventstore/commands/read.rb +23 -5
- data/lib/pg_eventstore/commands/read_grouped.rb +46 -0
- data/lib/pg_eventstore/commands/read_streams.rb +18 -0
- data/lib/pg_eventstore/commands/read_streams_paginated.rb +56 -0
- data/lib/pg_eventstore/commands/regular_stream_read_paginated.rb +4 -4
- data/lib/pg_eventstore/commands/revision_check/current_revision.rb +51 -0
- data/lib/pg_eventstore/commands/revision_check/event_type_revisions_comparison.rb +46 -0
- data/lib/pg_eventstore/commands/revision_check/expected_revision.rb +135 -0
- data/lib/pg_eventstore/commands/revision_check/stream_revision_check.rb +98 -0
- data/lib/pg_eventstore/commands/revision_check/stream_revision_comparison.rb +36 -0
- data/lib/pg_eventstore/commands/stream_revision.rb +14 -0
- data/lib/pg_eventstore/commands/system_stream_read_paginated.rb +4 -4
- data/lib/pg_eventstore/commands.rb +4 -2
- data/lib/pg_eventstore/config.rb +30 -9
- data/lib/pg_eventstore/connection.rb +21 -2
- data/lib/pg_eventstore/errors.rb +136 -10
- data/lib/pg_eventstore/event.rb +34 -2
- data/lib/pg_eventstore/event_deserializer.rb +5 -4
- data/lib/pg_eventstore/event_global_index.rb +118 -0
- data/lib/pg_eventstore/event_marker.rb +16 -0
- data/lib/pg_eventstore/event_marker_index.rb +25 -0
- data/lib/pg_eventstore/event_serializer.rb +6 -0
- data/lib/pg_eventstore/extensions/acts_as_configurable.rb +88 -0
- data/lib/pg_eventstore/extensions/options_defaults.rb +25 -0
- data/lib/pg_eventstore/extensions/options_extension.rb +2 -2
- data/lib/pg_eventstore/feature_marker.rb +18 -0
- data/lib/pg_eventstore/maintenance.rb +11 -6
- data/lib/pg_eventstore/middleware/event_tracing.rb +53 -0
- data/lib/pg_eventstore/partition.rb +6 -0
- data/lib/pg_eventstore/pg_connection.rb +70 -14
- data/lib/pg_eventstore/queries/event_marker_queries.rb +74 -0
- data/lib/pg_eventstore/queries/event_queries.rb +7 -93
- data/lib/pg_eventstore/queries/events_global_index_queries.rb +131 -0
- data/lib/pg_eventstore/queries/index_filtering_queries.rb +179 -0
- data/lib/pg_eventstore/queries/links_resolver.rb +4 -4
- data/lib/pg_eventstore/queries/maintenance_queries.rb +159 -42
- data/lib/pg_eventstore/queries/partition_queries.rb +45 -103
- data/lib/pg_eventstore/queries/replica_queries.rb +110 -0
- data/lib/pg_eventstore/queries/streams_global_index_queries.rb +163 -0
- data/lib/pg_eventstore/queries/transaction_queries.rb +52 -10
- data/lib/pg_eventstore/queries.rb +29 -1
- data/lib/pg_eventstore/query_builders/basic_filtering.rb +38 -5
- data/lib/pg_eventstore/query_builders/event_markers_filtering.rb +47 -0
- data/lib/pg_eventstore/query_builders/event_markers_index_filtering.rb +275 -0
- data/lib/pg_eventstore/query_builders/event_subscription_positions_filtering.rb +37 -0
- data/lib/pg_eventstore/query_builders/events_filtering.rb +15 -164
- data/lib/pg_eventstore/query_builders/events_global_index_filtering.rb +227 -0
- data/lib/pg_eventstore/query_builders/filters/collection.rb +324 -0
- data/lib/pg_eventstore/query_builders/filters/event_type_filter.rb +37 -0
- data/lib/pg_eventstore/query_builders/filters/filter_row.rb +54 -0
- data/lib/pg_eventstore/query_builders/filters/marker_filter.rb +20 -0
- data/lib/pg_eventstore/query_builders/filters/marker_filter_row.rb +49 -0
- data/lib/pg_eventstore/query_builders/filters/stream_filter.rb +48 -0
- data/lib/pg_eventstore/query_builders/index_based_events_filtering.rb +260 -0
- data/lib/pg_eventstore/query_builders/partitions_filtering.rb +175 -51
- data/lib/pg_eventstore/query_builders/read_cursor/stream_cursor.rb +122 -0
- data/lib/pg_eventstore/query_builders/streams_global_index_filtering.rb +83 -0
- data/lib/pg_eventstore/query_builders/subscription_events_filtering.rb +79 -0
- data/lib/pg_eventstore/query_strategy/async.rb +64 -0
- data/lib/pg_eventstore/query_strategy/foreground.rb +25 -0
- data/lib/pg_eventstore/query_strategy.rb +19 -0
- data/lib/pg_eventstore/raw_event.rb +46 -0
- data/lib/pg_eventstore/rspec/test_helpers.rb +21 -8
- data/lib/pg_eventstore/sql_builder.rb +87 -8
- data/lib/pg_eventstore/stream.rb +13 -16
- data/lib/pg_eventstore/stream_global_index.rb +28 -0
- data/lib/pg_eventstore/subscriptions/callback_handlers/events_processor_handlers.rb +5 -17
- data/lib/pg_eventstore/subscriptions/callback_handlers/events_subscription_position_worker_handlers.rb +36 -0
- data/lib/pg_eventstore/subscriptions/callback_handlers/subscription_feeder_handlers.rb +12 -0
- data/lib/pg_eventstore/subscriptions/callback_handlers/subscription_runner_handlers.rb +21 -7
- data/lib/pg_eventstore/subscriptions/events_processor.rb +20 -18
- data/lib/pg_eventstore/subscriptions/events_processor_consumer/multiple.rb +63 -0
- data/lib/pg_eventstore/subscriptions/events_processor_consumer/replica.rb +68 -0
- data/lib/pg_eventstore/subscriptions/events_processor_consumer/single.rb +62 -0
- data/lib/pg_eventstore/subscriptions/events_processor_consumer.rb +44 -0
- data/lib/pg_eventstore/subscriptions/events_subscription_position_worker.rb +68 -0
- data/lib/pg_eventstore/subscriptions/queries/event_subscription_position_queries.rb +177 -0
- data/lib/pg_eventstore/subscriptions/queries/subscription_queries.rb +78 -54
- data/lib/pg_eventstore/subscriptions/replica_subscription_handler.rb +140 -0
- data/lib/pg_eventstore/subscriptions/replica_subscription_runner.rb +9 -0
- data/lib/pg_eventstore/subscriptions/subscription.rb +2 -1
- data/lib/pg_eventstore/subscriptions/subscription_feed_strategies/collection.rb +36 -0
- data/lib/pg_eventstore/subscriptions/subscription_feed_strategies/index_read_strategy.rb +82 -0
- data/lib/pg_eventstore/subscriptions/subscription_feed_strategies/replication_strategy.rb +75 -0
- data/lib/pg_eventstore/subscriptions/subscription_feed_strategy.rb +31 -0
- data/lib/pg_eventstore/subscriptions/subscription_feeder.rb +24 -0
- data/lib/pg_eventstore/subscriptions/subscription_handler_performance.rb +4 -2
- data/lib/pg_eventstore/subscriptions/subscription_runner.rb +20 -9
- data/lib/pg_eventstore/subscriptions/subscription_runner_commands/reset_position.rb +1 -1
- data/lib/pg_eventstore/subscriptions/subscription_runners_feeder.rb +9 -18
- data/lib/pg_eventstore/subscriptions/subscriptions_lifecycle.rb +0 -12
- data/lib/pg_eventstore/subscriptions/subscriptions_manager.rb +74 -14
- data/lib/pg_eventstore/{subscriptions/synchronized_array.rb → synchronized_array.rb} +15 -0
- data/lib/pg_eventstore/tasks/setup.rake +2 -2
- data/lib/pg_eventstore/utils.rb +31 -0
- data/lib/pg_eventstore/version.rb +1 -1
- data/lib/pg_eventstore/web/application.rb +100 -16
- data/lib/pg_eventstore/web/paginator/base_collection.rb +5 -1
- data/lib/pg_eventstore/web/paginator/event_types_collection.rb +14 -4
- data/lib/pg_eventstore/web/paginator/events_collection.rb +29 -33
- data/lib/pg_eventstore/web/paginator/helpers.rb +16 -9
- data/lib/pg_eventstore/web/paginator/markers_collection.rb +48 -0
- data/lib/pg_eventstore/web/paginator/stream_contexts_collection.rb +13 -2
- data/lib/pg_eventstore/web/paginator/stream_ids_collection.rb +21 -11
- data/lib/pg_eventstore/web/paginator/stream_names_collection.rb +18 -4
- data/lib/pg_eventstore/web/paginator/streams_collection.rb +95 -0
- data/lib/pg_eventstore/web/public/javascripts/pg_eventstore.js +49 -22
- data/lib/pg_eventstore/web/subscriptions/set_collection.rb +1 -1
- data/lib/pg_eventstore/web/subscriptions/subscriptions.rb +1 -1
- data/lib/pg_eventstore/web/subscriptions/with_state/set_collection.rb +1 -1
- data/lib/pg_eventstore/web/subscriptions/with_state/subscriptions.rb +1 -1
- data/lib/pg_eventstore/web/views/home/dashboard.erb +11 -9
- data/lib/pg_eventstore/web/views/home/partials/event_filter.erb +18 -5
- data/lib/pg_eventstore/web/views/home/partials/events.erb +38 -1
- data/lib/pg_eventstore/web/views/home/partials/markers_filter.erb +18 -0
- data/lib/pg_eventstore/web/views/layouts/application.erb +6 -0
- data/lib/pg_eventstore/web/views/streams/index.erb +110 -0
- data/lib/pg_eventstore/web/views/streams/partials/streams.erb +11 -0
- data/lib/pg_eventstore/web/views/subscriptions/index.erb +4 -1
- data/lib/pg_eventstore/web.rb +2 -0
- data/lib/pg_eventstore.rb +23 -60
- data/pg_eventstore.gemspec +6 -4
- data/sig/interfaces/_raw_events_handler.rbs +3 -0
- data/sig/interfaces/subscription_handler.rbs +1 -1
- data/sig/pg/result.rbs +9 -0
- data/sig/pg_eventstore/async_runner.rbs +13 -0
- data/sig/pg_eventstore/basic_config.rbs +9 -0
- data/sig/pg_eventstore/chunks/chunk.rbs +13 -0
- data/sig/pg_eventstore/chunks/read_api_events_index_chunk.rbs +30 -0
- data/sig/pg_eventstore/chunks/replica_events_index_chunk.rbs +11 -0
- data/sig/pg_eventstore/chunks/repository.rbs +22 -0
- data/sig/pg_eventstore/chunks/subscription_checkpoint_chunk.rbs +18 -0
- data/sig/pg_eventstore/chunks/subscription_events_index_chunk.rbs +37 -0
- data/sig/pg_eventstore/client.rbs +40 -42
- data/sig/pg_eventstore/commands/append.rbs +11 -25
- data/sig/pg_eventstore/commands/event_modifiers/prepare_link_event.rbs +9 -12
- data/sig/pg_eventstore/commands/event_modifiers/prepare_regular_event.rbs +5 -4
- data/sig/pg_eventstore/commands/link_to.rbs +6 -11
- data/sig/pg_eventstore/commands/read.rbs +2 -5
- data/sig/pg_eventstore/commands/read_grouped.rbs +7 -0
- data/sig/pg_eventstore/commands/read_streams.rbs +7 -0
- data/sig/pg_eventstore/commands/read_streams_paginated.rbs +16 -0
- data/sig/pg_eventstore/commands/regular_stream_read_paginated.rbs +9 -17
- data/sig/pg_eventstore/commands/revision_check/current_revision.rbs +25 -0
- data/sig/pg_eventstore/commands/revision_check/event_type_revisions_comparison.rbs +14 -0
- data/sig/pg_eventstore/commands/revision_check/expected_revision.rbs +67 -0
- data/sig/pg_eventstore/commands/revision_check/stream_revision_check.rbs +20 -0
- data/sig/pg_eventstore/commands/revision_check/stream_revision_comparison.rbs +9 -0
- data/sig/pg_eventstore/commands/stream_revision.rbs +7 -0
- data/sig/pg_eventstore/commands/system_stream_read_paginated.rbs +9 -14
- data/sig/pg_eventstore/config.rbs +15 -6
- data/sig/pg_eventstore/connection.rbs +11 -18
- data/sig/pg_eventstore/errors.rbs +64 -34
- data/sig/pg_eventstore/event.rbs +16 -2
- data/sig/pg_eventstore/event_deserializer.rbs +5 -10
- data/sig/pg_eventstore/event_global_index.rbs +60 -0
- data/sig/pg_eventstore/event_marker.rbs +9 -0
- data/sig/pg_eventstore/event_marker_index.rbs +12 -0
- data/sig/pg_eventstore/extensions/acts_as_configurable.rbs +29 -0
- data/sig/pg_eventstore/extensions/options_defaults.rbs +7 -0
- data/sig/pg_eventstore/feature_marker.rbs +10 -0
- data/sig/pg_eventstore/maintenance.rbs +12 -8
- data/sig/pg_eventstore/middleware/event_trace.rbs +14 -0
- data/sig/pg_eventstore/partition.rbs +2 -4
- data/sig/pg_eventstore/pg_connection.rbs +8 -0
- data/sig/pg_eventstore/queries/event_marker_queries.rbs +21 -0
- data/sig/pg_eventstore/queries/event_queries.rbs +4 -36
- data/sig/pg_eventstore/queries/events_global_index_queries.rbs +37 -0
- data/sig/pg_eventstore/queries/index_filtering_queries.rbs +50 -0
- data/sig/pg_eventstore/queries/links_resolver.rbs +5 -9
- data/sig/pg_eventstore/queries/maintenance_queries.rbs +12 -9
- data/sig/pg_eventstore/queries/partition_queries.rbs +32 -67
- data/sig/pg_eventstore/queries/replica_queries.rbs +31 -0
- data/sig/pg_eventstore/queries/streams_global_index_queries.rbs +39 -0
- data/sig/pg_eventstore/queries/transaction_queries.rbs +2 -0
- data/sig/pg_eventstore/queries.rbs +11 -21
- data/sig/pg_eventstore/query_builders/basic_filtering.rbs +10 -3
- data/sig/pg_eventstore/query_builders/event_markers_filtering.rbs +17 -0
- data/sig/pg_eventstore/query_builders/event_markers_index_filtering.rbs +69 -0
- data/sig/pg_eventstore/query_builders/event_subscription_positions_filtering.rbs +15 -0
- data/sig/pg_eventstore/query_builders/events_filtering_query.rbs +9 -51
- data/sig/pg_eventstore/query_builders/events_global_index_filtering.rbs +68 -0
- data/sig/pg_eventstore/query_builders/filters/collection.rbs +84 -0
- data/sig/pg_eventstore/query_builders/filters/event_type_filter.rbs +19 -0
- data/sig/pg_eventstore/query_builders/filters/filter_row.rbs +21 -0
- data/sig/pg_eventstore/query_builders/filters/marker_filter.rbs +13 -0
- data/sig/pg_eventstore/query_builders/filters/marker_filter_row.rbs +19 -0
- data/sig/pg_eventstore/query_builders/filters/stream_filter.rbs +24 -0
- data/sig/pg_eventstore/query_builders/index_based_events_filtering.rbs +60 -0
- data/sig/pg_eventstore/query_builders/partitions_filtering.rbs +29 -10
- data/sig/pg_eventstore/query_builders/read_cursor/stream_cursor.rbs +47 -0
- data/sig/pg_eventstore/query_builders/streams_global_index_filtering.rbs +27 -0
- data/sig/pg_eventstore/query_builders/subscription_events_filtering.rbs +26 -0
- data/sig/pg_eventstore/query_strategy/async.rbs +17 -0
- data/sig/pg_eventstore/query_strategy/foreground.rbs +11 -0
- data/sig/pg_eventstore/query_strategy.rbs +7 -0
- data/sig/pg_eventstore/raw_event.rbs +20 -0
- data/sig/pg_eventstore/sql_builder.rbs +32 -10
- data/sig/pg_eventstore/stream.rbs +10 -18
- data/sig/pg_eventstore/stream_global_index.rbs +14 -0
- data/sig/pg_eventstore/subscriptions/callback_handlers/events_processor_handlers.rbs +5 -4
- data/sig/pg_eventstore/subscriptions/callback_handlers/events_subscription_position_worker_handlers.rbs +9 -0
- data/sig/pg_eventstore/subscriptions/callback_handlers/subscription_feeder_handlers.rbs +17 -12
- data/sig/pg_eventstore/subscriptions/callback_handlers/subscription_runner_handlers.rbs +17 -6
- data/sig/pg_eventstore/subscriptions/event_subscription_position_queries.rbs +30 -0
- data/sig/pg_eventstore/subscriptions/events_processor.rbs +12 -5
- data/sig/pg_eventstore/subscriptions/events_processor_consumer/multiple.rbs +17 -0
- data/sig/pg_eventstore/subscriptions/events_processor_consumer/replica.rbs +17 -0
- data/sig/pg_eventstore/subscriptions/events_processor_consumer/single.rbs +17 -0
- data/sig/pg_eventstore/subscriptions/events_processor_consumer.rbs +14 -0
- data/sig/pg_eventstore/subscriptions/events_subscription_position_worker.rbs +28 -0
- data/sig/pg_eventstore/subscriptions/queries/subscription_queries.rbs +7 -39
- data/sig/pg_eventstore/subscriptions/replica_subscription_handler.rbs +33 -0
- data/sig/pg_eventstore/subscriptions/replica_subscription_runner.rbs +4 -0
- data/sig/pg_eventstore/subscriptions/subscription_feed_strategy/collection.rbs +14 -0
- data/sig/pg_eventstore/subscriptions/subscription_feed_strategy/index_read_strategy.rbs +23 -0
- data/sig/pg_eventstore/subscriptions/subscription_feed_strategy/replication_strategy.rbs +23 -0
- data/sig/pg_eventstore/subscriptions/subscription_feed_strategy.rbs +11 -0
- data/sig/pg_eventstore/subscriptions/subscription_feeder.rbs +13 -10
- data/sig/pg_eventstore/subscriptions/subscription_handler_performance.rbs +1 -1
- data/sig/pg_eventstore/subscriptions/subscription_runner.rbs +13 -2
- data/sig/pg_eventstore/subscriptions/subscription_runners_feeder.rbs +1 -8
- data/sig/pg_eventstore/subscriptions/subscriptions_lifecycle.rbs +4 -6
- data/sig/pg_eventstore/subscriptions/subscriptions_manager.rbs +29 -43
- data/sig/pg_eventstore/synchronized_array.rbs +4 -0
- data/sig/pg_eventstore/utils.rbs +10 -11
- data/sig/pg_eventstore/web/application.rbs +13 -3
- data/sig/pg_eventstore/web/paginator/base_collection.rbs +2 -0
- data/sig/pg_eventstore/web/paginator/event_types_collection.rbs +4 -0
- data/sig/pg_eventstore/web/paginator/events_collection.rbs +11 -11
- data/sig/pg_eventstore/web/paginator/helpers.rbs +6 -15
- data/sig/pg_eventstore/web/paginator/markers_collection.rbs +13 -0
- data/sig/pg_eventstore/web/paginator/stream_contexts_collection.rbs +4 -0
- data/sig/pg_eventstore/web/paginator/stream_names_collection.rbs +4 -0
- data/sig/pg_eventstore/web/paginator/streams_collection.rbs +30 -0
- data/sig/pg_eventstore.rbs +8 -26
- metadata +175 -20
- data/Dockerfile +0 -3
- data/lib/pg_eventstore/commands/all_stream_read_grouped.rb +0 -69
- data/lib/pg_eventstore/commands/regular_stream_read_grouped.rb +0 -31
- data/lib/pg_eventstore/subscriptions/queries/subscription_service_queries.rb +0 -78
- data/lib/pg_eventstore/web/views/home/partials/system_stream_filter.erb +0 -15
- data/sig/pg_eventstore/commands/all_stream_read_grouped.rbs +0 -16
- data/sig/pg_eventstore/commands/regular_stream_read_grouped.rbs +0 -8
- data/sig/pg_eventstore/subscriptions/queries/subscription_service_queries.rbs +0 -19
- data/sig/pg_eventstore/subscriptions/synchronized_array.rbs +0 -4
- /data/sig/interfaces/{_raw_event_handler.rbs → raw_event_handler.rbs} +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4425f2f4cffd24b06156465726034e4c8da383fed7f0576837851a65390068e0
|
|
4
|
+
data.tar.gz: bb809d708eaea98368d54bae14a8d35f36265a7a5ad66c4b8fd9b5dc57293163
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e86a98610d16b95eeb4bffa5a3b0d74055ac7901a30f20d297aee1b37786e06f94ff483c135f99df255cd23f50b3cac4d9360c6338ccbdab7d58d14b05fc5578
|
|
7
|
+
data.tar.gz: cdfe9c6093814265d91905f1405ff39bbd347a4e844c75961f3b3db56eb0fb4f32537b4cd26a0bb7c46b82abb21d25cb2aa7831623466cd3e2a3d5d50caf4a42
|
data/.rubocop.yml
CHANGED
|
@@ -27,7 +27,7 @@ RSpec/IndexedLet:
|
|
|
27
27
|
Enabled: false
|
|
28
28
|
|
|
29
29
|
RSpec/NestedGroups:
|
|
30
|
-
|
|
30
|
+
Enabled: false
|
|
31
31
|
|
|
32
32
|
RSpec/LetSetup:
|
|
33
33
|
Enabled: false
|
|
@@ -124,3 +124,12 @@ Gemspec/RequiredRubyVersion:
|
|
|
124
124
|
|
|
125
125
|
Gemspec/RequireMFA:
|
|
126
126
|
Enabled: false
|
|
127
|
+
|
|
128
|
+
Style/StructInheritance:
|
|
129
|
+
Enabled: false
|
|
130
|
+
|
|
131
|
+
Lint/NonLocalExitFromIterator:
|
|
132
|
+
Enabled: false
|
|
133
|
+
|
|
134
|
+
Style/RegexpLiteral:
|
|
135
|
+
Enabled: false
|
data/CHANGELOG.md
CHANGED
|
@@ -1,17 +1,141 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [3.0.0]
|
|
4
|
+
|
|
5
|
+
- New feature: pg_eventstore replication
|
|
6
|
+
- **Breaking change**: drop support of Ruby v3.2. The gem now requires Ruby v3.3+
|
|
7
|
+
- New feature: event tracing. You can now configure pg_eventstore to trace causation dependencies of events.
|
|
8
|
+
Read more [here](docs/event_tracing.md)
|
|
9
|
+
- **Breaking change**: when event is persisted using `#append_to_stream` - it now gets deserialized via each registered
|
|
10
|
+
middleware by default. Previously this wasn't the case - the deserialization phase was skipped. Such behavior was
|
|
11
|
+
creating ambiguity about assumptions when deserialization happens. If you need old behavior - you have to create
|
|
12
|
+
another middleware class which skips deserialization when publishing events and use it instead. Example:
|
|
13
|
+
Let's say you have this middleware configured
|
|
14
|
+
```ruby
|
|
15
|
+
class MyMiddleware
|
|
16
|
+
include PgEventstore::Middleware
|
|
17
|
+
|
|
18
|
+
def serialize(event)
|
|
19
|
+
# do something with event before persisting it
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def deserialize(event)
|
|
23
|
+
# do something with event after reading it from db
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
PgEventstore.configure do |config|
|
|
28
|
+
config.middleware = { my_middleware: MyMiddleware.new }
|
|
29
|
+
end
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Now define another middleware that has empty `#deserialize` method
|
|
33
|
+
|
|
34
|
+
```ruby
|
|
35
|
+
class MyMiddlewareWithoutDeserialize < MyMiddleware
|
|
36
|
+
def deserialize(event)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
PgEventstore.configure do |config|
|
|
41
|
+
config.middleware = {
|
|
42
|
+
my_middleware: MyMiddleware.new,
|
|
43
|
+
my_middleware_wo_deserialize: MyMiddlewareWithoutDeserialize.new
|
|
44
|
+
}
|
|
45
|
+
end
|
|
46
|
+
```
|
|
47
|
+
and use only it when publishing events:
|
|
48
|
+
|
|
49
|
+
```ruby
|
|
50
|
+
PgEventstore.client.append_to_stream(stream, event, middlewares: [:my_middleware_wo_deserialize])
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Alternatively, if you don't rely on `#multiple`, you can create another config specially for write operations:
|
|
54
|
+
|
|
55
|
+
```ruby
|
|
56
|
+
# this is your default
|
|
57
|
+
PgEventstore.configure do |config|
|
|
58
|
+
config.middleware = { my_middleware: MyMiddleware.new }
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
PgEventstore.configure(name: :write) do |config|
|
|
62
|
+
config.middleware = { my_middleware: MyMiddlewareWithoutDeserialize.new }
|
|
63
|
+
end
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
and use it for write operations:
|
|
67
|
+
|
|
68
|
+
```ruby
|
|
69
|
+
PgEventstore.client(:write).append_to_stream(stream, event)
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
- **Breaking change**: `Event#id` uniqueness is no longer guaranteed. It was dropped because there is not much usage of
|
|
73
|
+
it internally. The default value was moved from the database(it was `gen_random_uuid()`) to the application level and
|
|
74
|
+
is `SecureRandom.uuid_v7` now.
|
|
75
|
+
- **Breaking change**: event types, stream attributes, event metadata keys, markers that start from `▒`(`"\u2592"`
|
|
76
|
+
Unicode character) character are now reserved by pg_eventstore. It is less likely you have any, but if you do - you have
|
|
77
|
+
to adjust your implementation to no longer rely on it.
|
|
78
|
+
- New feature: event markers. You can now mark an event and later use those markers to read events, build a projection
|
|
79
|
+
using subscriptions or validate stream revision scoped to an event type and specific markers when publishing events as
|
|
80
|
+
a part of Dynamic Consistency Boundaries. Find more in [docs](docs/appending_events.md#event-markers)
|
|
81
|
+
- New config option `config.events_subscription_position_update_interval`. See more
|
|
82
|
+
in [Configuration](docs/configuration.md) docs
|
|
83
|
+
- **Breaking change**: `:from_position` option of `SubscriptionManager#subscribe`, "Current position" column in admin
|
|
84
|
+
web UI, "Reset position" form in admin web UI now refers to the event subscription position instead
|
|
85
|
+
`Event#global_position`. See more information in related
|
|
86
|
+
docs [Subscription position](docs/subscriptions.md#subscription-position)
|
|
87
|
+
- **Breaking change**: Drop `pg_cron` dependency
|
|
88
|
+
- Remove deprecated `SubscriptionsManager#force_lock!`
|
|
89
|
+
- New feature: explicit support of Dynamic Consistency Boundaries when publishing events. You can now provide "event
|
|
90
|
+
type"-to-"expected stream revision" hash map into `:expected_revision` option. It allows to validate against stream
|
|
91
|
+
revision at the specific event type instead validating the whole stream. Example:
|
|
92
|
+
`PgEventstore.client.append_to_stream(stream, events, options: { expected_revision: { 'Foo' => 10, 'Bar' => 20 } })`
|
|
93
|
+
- **Breaking change**: `WrongExpectedRevisionError#new` now requires `:verdict` keyword argument.
|
|
94
|
+
`Client#append_to_stream` now also may raise `WrongExpectedTypesRevisionError` error in case `:expected_revision`
|
|
95
|
+
option is "event type"-to-"expected stream revision" hash map
|
|
96
|
+
- Remove any practical limit of `Event#stream_revision` by changing its type to `bigint`. Stream size can be practically
|
|
97
|
+
unreachable now
|
|
98
|
+
- Fix issue when incomplete transaction block may be interrupted half way and commited successfully. The issue is
|
|
99
|
+
related to incorrect transaction termination flow during non-graceful thread shutdown(e.g. via `Thread.exit`)
|
|
100
|
+
- New feature: `Client#stream_revision` allows to quickly get stream's revision. Example:
|
|
101
|
+
`PgEventstore.client.stream_revision(stream) #=> number, greater than or equal to 0 or -1 if stream does not exist`
|
|
102
|
+
- **Breaking change**: `Client#read_grouped` now requires to provide `event_types` filter option explicitly. Example:
|
|
103
|
+
`PgEventstore.client.read_grouped(stream, options: { filter: { event_types: ['Foo', 'Bar'] } })`
|
|
104
|
+
- New feature: Subscription event types filter now support prefixes. So, if you have subscriptions like
|
|
105
|
+
`manager.subscribe('MyAwesomeSubscription', handler: my_handler, options: { filter: { event_types: ['Foo1', 'Foo2', 'Foo3'] } })`,
|
|
106
|
+
you can replace its filter as follows: `{ event_types: [{ prefix: 'Foo' }] }`. **Read API does not support this
|
|
107
|
+
feature yet**
|
|
108
|
+
- New feature: Read API now supports `:to_position`(and `:to_revision` when reading from specific stream) option. Use it
|
|
109
|
+
if you want to limit your result alongside `:max_count` option. Example:
|
|
110
|
+
`PgEventstore.client.read(PgEventstore::Stream.all_stream, options: { from_position: 100, to_position: 200 })`
|
|
111
|
+
- **Breaking change**: `Middleware#serialize` is now called outside SQL transaction that inserts an event tuple.
|
|
112
|
+
Previously it was happening right before an `INSERT` statement
|
|
113
|
+
- **Breaking change**: Database structure and the implementation of `#append_to_stream` was changed in a way it is not
|
|
114
|
+
compatible with v2. Public API stays the same
|
|
115
|
+
- New feature: allow subscription to process events in batches. You can now provide `in_batches: true` to `#subscribe`
|
|
116
|
+
to yield an array of events. See [docs](docs/subscriptions.md#processing-events-in-batches) for more info
|
|
117
|
+
- Introduce `PgEventstore::BasicConfig` and `PgEventstore::Extensions::ActsAsConfigurable` to allow to easily create
|
|
118
|
+
configurable objects
|
|
119
|
+
|
|
3
120
|
## [2.0.0]
|
|
4
121
|
|
|
5
122
|
- **Breaking change**: `pg_eventstore` now requires [pg_cron](https://github.com/citusdata/pg_cron) extension
|
|
6
123
|
- **Breaking change**: `pg_eventstore` now requires PostgreSQL v16+
|
|
7
124
|
- Greatly decreased the number of connections, used by `pg_eventstore` subscriptions
|
|
8
125
|
- **Breaking change**: drop support of Ruby v3.0 and v3.1. The gem now requires Ruby v3.2+
|
|
9
|
-
- **Breaking change**: `PgEventstore::Extensions::OptionsExtension::Options` class is no longer a child of `Set` class -
|
|
126
|
+
- **Breaking change**: `PgEventstore::Extensions::OptionsExtension::Options` class is no longer a child of `Set` class -
|
|
127
|
+
it has independent implementation now
|
|
10
128
|
- Add support of Ruby v4.0
|
|
11
|
-
- `Client#multiple` method now accepts `read_only` keyword argument. When it is set to true - transaction is run in
|
|
12
|
-
-
|
|
129
|
+
- `Client#multiple` method now accepts `read_only` keyword argument. When it is set to true - transaction is run in
|
|
130
|
+
read-only mode
|
|
131
|
+
- **Breaking change**: rework links implementation. This change boosts performance, but affects the database structure,
|
|
132
|
+
so your previous database dumps become incompatible with this change. `PgEventstore::Event#link_id` was replaced by
|
|
133
|
+
`PgEventstore::Event#link_global_position`
|
|
13
134
|
|
|
14
|
-
Changes above require you to run migrations - `bundle exec rake pg_eventstore:migrate`. One of the migrations also
|
|
135
|
+
Changes above require you to run migrations - `bundle exec rake pg_eventstore:migrate`. One of the migrations also
|
|
136
|
+
migrates existing data using several concurrent workers(threads). You can adjust the number of workers using
|
|
137
|
+
`CONCURRENCY` environment variable. Default number of concurrent workers is `10`. **Migrations require a downtime - no
|
|
138
|
+
reads/writes should be performed during the time of the migrations, so plan your maintenance downtime accordingly.**
|
|
15
139
|
|
|
16
140
|
## [1.13.4]
|
|
17
141
|
|
|
@@ -31,7 +155,8 @@ Changes above require you to run migrations - `bundle exec rake pg_eventstore:mi
|
|
|
31
155
|
|
|
32
156
|
## [1.13.0]
|
|
33
157
|
|
|
34
|
-
- Introduce automatic subscriptions recovery from connection errors. This way if a subscription process loses the
|
|
158
|
+
- Introduce automatic subscriptions recovery from connection errors. This way if a subscription process loses the
|
|
159
|
+
connection to the database - it will be trying to reconnect until the connection is restored.
|
|
35
160
|
- Resolve ambiguity in usage of `PgEventstore.config` method. It now returns the frozen object.
|
|
36
161
|
|
|
37
162
|
## [1.12.0]
|
|
@@ -40,12 +165,17 @@ Changes above require you to run migrations - `bundle exec rake pg_eventstore:mi
|
|
|
40
165
|
|
|
41
166
|
## [1.11.0]
|
|
42
167
|
|
|
43
|
-
- Add a global position that caused an error to the subscription's error JSON info. This will help you understand what
|
|
168
|
+
- Add a global position that caused an error to the subscription's error JSON info. This will help you understand what
|
|
169
|
+
event caused your subscription to fail.
|
|
44
170
|
- Improve long payloads in JSON preview in admin web UI in the way it does not moves content out of the visible area.
|
|
45
|
-
- Admin UI: adjust events filtering and displaying of stream context, stream name, stream id and event type when values
|
|
171
|
+
- Admin UI: adjust events filtering and displaying of stream context, stream name, stream id and event type when values
|
|
172
|
+
of them contain empty strings or non-displayable characters
|
|
46
173
|
|
|
47
174
|
## [1.10.0]
|
|
48
|
-
|
|
175
|
+
|
|
176
|
+
- Admin UI: Adjust `SubscriptionSet` "Stop"/"Delete" buttons appearance. Now if `SubscriptionsSet` is not alive anymore(
|
|
177
|
+
the related process is dead or does not exist anymore) - "Delete" button is shown. If `SubscriptionSet` is alive - "
|
|
178
|
+
Stop" button is shown
|
|
49
179
|
- Admin IU: fixed several potential XSS vulnerabilities
|
|
50
180
|
- Admin IU: Add "Copy to clipboard" button near stream id that copies ruby stream definition
|
|
51
181
|
- Admin UI: allow deletion of streams with empty attribute values
|
|
@@ -57,23 +187,33 @@ Changes above require you to run migrations - `bundle exec rake pg_eventstore:mi
|
|
|
57
187
|
- Add "Delete event" and "Delete stream" buttons into admin UI
|
|
58
188
|
|
|
59
189
|
## [1.8.0]
|
|
60
|
-
|
|
190
|
+
|
|
191
|
+
- Introduce default config for admin web UI. Now if you define `:admin_web_ui` config - it will be preferred over
|
|
192
|
+
default config
|
|
61
193
|
- Fix pagination of events in admin UI
|
|
62
194
|
- Improve partial index for `$streams` system stream
|
|
63
195
|
|
|
64
196
|
## [1.7.0]
|
|
197
|
+
|
|
65
198
|
- Implement reading from `"$streams"` system stream
|
|
66
199
|
- Disable Host authorization introduced in sinatra v4.1
|
|
67
200
|
|
|
68
201
|
## [1.6.0]
|
|
69
|
-
|
|
202
|
+
|
|
203
|
+
- Introduce subscriptions CLI. Type `pg-eventstore subscriptions --help` to see available commands. The main purpose of
|
|
204
|
+
it is to provide the single way to start/stop subscription processes.
|
|
205
|
+
Check [Subscriptions](docs/subscriptions.md#creating-a-subscription) docs about the new way to start and keep running
|
|
206
|
+
a subscriptions process.
|
|
70
207
|
|
|
71
208
|
## [1.5.0]
|
|
209
|
+
|
|
72
210
|
- Add ability to toggle link events in the admin UI
|
|
73
211
|
- Mark linked events in the admin UI with "link" icon
|
|
74
212
|
|
|
75
213
|
## [1.4.0]
|
|
76
|
-
|
|
214
|
+
|
|
215
|
+
- Add an ability to configure subscription graceful shutdown timeout globally and per subscription. Default value is 15
|
|
216
|
+
seconds. Previously it was hardcoded to 5 seconds. Examples:
|
|
77
217
|
|
|
78
218
|
```ruby
|
|
79
219
|
# Set it globally, for all subscriptions
|
|
@@ -90,18 +230,24 @@ subscriptions_manager.subscribe(
|
|
|
90
230
|
```
|
|
91
231
|
|
|
92
232
|
## [1.3.4]
|
|
93
|
-
|
|
233
|
+
|
|
234
|
+
- Fix `NoMethodError` error in `Client#read_paginated` when stream does not exist or when there are no events matching
|
|
235
|
+
the given filter
|
|
94
236
|
|
|
95
237
|
## [1.3.3]
|
|
238
|
+
|
|
96
239
|
- Adjust default value of `subscription_max_retries` setting
|
|
97
240
|
|
|
98
241
|
## [1.3.2]
|
|
242
|
+
|
|
99
243
|
- Fix UI when switching subscription status
|
|
100
244
|
|
|
101
245
|
## [1.3.1]
|
|
246
|
+
|
|
102
247
|
- Swap "Search" button and "Add filter" button on Dashboard page
|
|
103
248
|
|
|
104
249
|
## [1.3.0]
|
|
250
|
+
|
|
105
251
|
- Add ability to filter subscriptions by state in admin UI
|
|
106
252
|
- Reset error-related subscription's attributes on subscription restore
|
|
107
253
|
- Reset total processed events number when user changes subscription's position
|
|
@@ -109,9 +255,12 @@ subscriptions_manager.subscribe(
|
|
|
109
255
|
- Relax sinatra version requirement to v3+
|
|
110
256
|
|
|
111
257
|
## [1.2.0]
|
|
258
|
+
|
|
112
259
|
- Implement `failed_subscription_notifier` subscription hook.
|
|
113
260
|
|
|
114
|
-
Now you are able to define a function that is called when subscription fails and no longer can be automatically
|
|
261
|
+
Now you are able to define a function that is called when subscription fails and no longer can be automatically
|
|
262
|
+
restarted because it hit max number of retries. You can define the hook globally in the config and per subscription.
|
|
263
|
+
Examples:
|
|
115
264
|
|
|
116
265
|
```ruby
|
|
117
266
|
PgEventstore.configure do |config|
|
|
@@ -135,36 +284,48 @@ subscriptions_manager.subscribe(
|
|
|
135
284
|
```
|
|
136
285
|
|
|
137
286
|
## [1.1.5]
|
|
138
|
-
|
|
287
|
+
|
|
288
|
+
- Review the way to handle SubscriptionAlreadyLockedError error. This removes noise when attempting to lock an already
|
|
289
|
+
locked subscription.
|
|
139
290
|
|
|
140
291
|
## [1.1.4]
|
|
292
|
+
|
|
141
293
|
- Add rbs signatures
|
|
142
294
|
|
|
143
295
|
## [1.1.3]
|
|
296
|
+
|
|
144
297
|
- Fix issue with assets caching between different gem's versions
|
|
145
298
|
|
|
146
299
|
## [1.1.2]
|
|
300
|
+
|
|
147
301
|
- Improve web app compatibility with rails
|
|
148
302
|
|
|
149
303
|
## [1.1.1]
|
|
304
|
+
|
|
150
305
|
- Allow case insensitive search by context, stream name and event type in admin UI
|
|
151
306
|
|
|
152
307
|
## [1.1.0]
|
|
308
|
+
|
|
153
309
|
- Add "Reset position" button on Subscriptions Admin UI page
|
|
154
310
|
|
|
155
|
-
**Note** This release includes a migration to support new functional. Please don't forget to run
|
|
311
|
+
**Note** This release includes a migration to support new functional. Please don't forget to run
|
|
312
|
+
`rake pg_eventstore:migrate` to apply latest db changes.
|
|
156
313
|
|
|
157
314
|
## [1.0.4]
|
|
315
|
+
|
|
158
316
|
- Fix bug which caused slow Subscriptions to stop processing new events
|
|
159
317
|
- Optimize Subscriptions update queries
|
|
160
318
|
|
|
161
319
|
## [1.0.3]
|
|
320
|
+
|
|
162
321
|
- Do no update `Subscription#last_chunk_fed_at` if the chunk is empty
|
|
163
322
|
|
|
164
323
|
## [1.0.2]
|
|
324
|
+
|
|
165
325
|
- UI: Fix opening of SubscriptionsSet tab of non-existing SubscriptionsSet
|
|
166
326
|
|
|
167
327
|
## [1.0.1]
|
|
328
|
+
|
|
168
329
|
- Adjust assets urls to correctly act when mounting sinatra app under non-root url
|
|
169
330
|
|
|
170
331
|
## [1.0.0]
|
|
@@ -202,7 +363,8 @@ subscriptions_manager.subscribe(
|
|
|
202
363
|
|
|
203
364
|
## [0.8.0] - 2024-02-20
|
|
204
365
|
|
|
205
|
-
- Allow float values for `subscription_pull_interval`. The default value of it was also set to `1.0`(it was `2`
|
|
366
|
+
- Allow float values for `subscription_pull_interval`. The default value of it was also set to `1.0`(it was `2`
|
|
367
|
+
previously)
|
|
206
368
|
|
|
207
369
|
## [0.7.2] - 2024-02-14
|
|
208
370
|
|
|
@@ -214,7 +376,8 @@ subscriptions_manager.subscribe(
|
|
|
214
376
|
|
|
215
377
|
## [0.7.0] - 2024-02-09
|
|
216
378
|
|
|
217
|
-
- Refactor `pg_eventstore:create` and `pg_eventstore:drop` rake tasks. They now actually create/drop the database. You
|
|
379
|
+
- Refactor `pg_eventstore:create` and `pg_eventstore:drop` rake tasks. They now actually create/drop the database. You
|
|
380
|
+
will have to execute `delete from migrations where number > 6` query before deploying this version.
|
|
218
381
|
- Drop legacy migrations
|
|
219
382
|
|
|
220
383
|
## [0.6.0] - 2024-02-08
|
|
@@ -259,9 +422,11 @@ subscriptions_manager.subscribe(
|
|
|
259
422
|
|
|
260
423
|
## [0.2.4] - 2023-12-20
|
|
261
424
|
|
|
262
|
-
Due to performance issues under certain circumstances, searching by event type was giving bad performance. I decided to
|
|
425
|
+
Due to performance issues under certain circumstances, searching by event type was giving bad performance. I decided to
|
|
426
|
+
extract `type` column from `events` table into separated table. **No breaking changes in public API though.**
|
|
263
427
|
|
|
264
|
-
**Warning** The migrations this version has, requires you to shut down applications that use `pg_eventstore` and only
|
|
428
|
+
**Warning** The migrations this version has, requires you to shut down applications that use `pg_eventstore` and only
|
|
429
|
+
then run `rake pg_eventstore:migrate`.
|
|
265
430
|
|
|
266
431
|
## [0.2.3] - 2023-12-18
|
|
267
432
|
|
|
@@ -273,7 +438,8 @@ Due to performance issues under certain circumstances, searching by event type w
|
|
|
273
438
|
|
|
274
439
|
## [0.2.1] - 2023-12-14
|
|
275
440
|
|
|
276
|
-
Under certain circumstances `PG::TRSerializationFailure` exception wasn't retried. Adjust connection's states list to
|
|
441
|
+
Under certain circumstances `PG::TRSerializationFailure` exception wasn't retried. Adjust connection's states list to
|
|
442
|
+
fix that.
|
|
277
443
|
|
|
278
444
|
## [0.2.0] - 2023-12-14
|
|
279
445
|
|
data/README.md
CHANGED
|
@@ -4,11 +4,21 @@ Implements database and API to store and read events in event sourced systems.
|
|
|
4
4
|
|
|
5
5
|
## Requirements
|
|
6
6
|
|
|
7
|
-
- `pg_eventstore` requires a PostgreSQL v16
|
|
8
|
-
- `pg_evenstore` requires a separate
|
|
7
|
+
- `pg_eventstore` requires a PostgreSQL v16+.
|
|
8
|
+
- `pg_evenstore` requires a separate database. However, it is recommended that you spin it up on a separate PostgreSQL instance in a production environment.
|
|
9
9
|
- `pg_eventstore` requires `default_transaction_isolation` server config option to be set to `'read committed'` (default behavior). Having this value set to move strict isolation level may result in unexpected behavior.
|
|
10
10
|
- It is recommended to use a connection pooler (for example [PgBouncer](https://www.pgbouncer.org/)) in `transaction` pool mode to lower the load on a database.
|
|
11
|
-
- `pg_eventstore` requires ruby v3+. The development of this gem is targeted at [current](https://endoflife.date/ruby) ruby versions.
|
|
11
|
+
- `pg_eventstore` requires ruby v3.3+. The development of this gem is targeted at [current](https://endoflife.date/ruby) ruby versions.
|
|
12
|
+
|
|
13
|
+
### Migrating to v3
|
|
14
|
+
|
|
15
|
+
If you are migrating from v2 - please don't forget to delete cron jobs and `pg_cron` extension after migration to v3.
|
|
16
|
+
You can remove cron jobs as follows:
|
|
17
|
+
|
|
18
|
+
```sql
|
|
19
|
+
SELECT cron.unschedule('prune_eventstore_events_horizon');
|
|
20
|
+
SELECT cron.unschedule('delete-job-run-details');
|
|
21
|
+
```
|
|
12
22
|
|
|
13
23
|
## Installation
|
|
14
24
|
|
|
@@ -47,26 +57,22 @@ Documentation chapters:
|
|
|
47
57
|
- [Appending events](docs/appending_events.md)
|
|
48
58
|
- [Linking events](docs/linking_events.md)
|
|
49
59
|
- [Reading events](docs/reading_events.md)
|
|
60
|
+
- [Reading streams](docs/reading_streams.md)
|
|
61
|
+
- [Tracing events](docs/event_tracing.md)
|
|
50
62
|
- [Subscriptions](docs/subscriptions.md)
|
|
51
63
|
- [Maintenance functions](docs/maintenance.md)
|
|
52
64
|
- [Writing middlewares](docs/writing_middleware.md)
|
|
53
65
|
- [How to make multiple commands atomic](docs/multiple_commands.md)
|
|
54
66
|
- [Admin UI](docs/admin_ui.md)
|
|
67
|
+
- [Replication](docs/replication.md)
|
|
68
|
+
|
|
69
|
+
To help your AI assistant to better recognize the capabilities of this gem - there is a crafted [instructions](docs/AGENTS.fragment.md)
|
|
70
|
+
you can include into your `AGENTS.md`.
|
|
55
71
|
|
|
56
72
|
## CLI
|
|
57
73
|
|
|
58
74
|
The gem is shipped with its own CLI. Use `pg-eventstore --help` to find out its capabilities.
|
|
59
75
|
|
|
60
|
-
## Maintenance
|
|
61
|
-
|
|
62
|
-
You may want to backup your eventstore database. It is important to mention that you don't want to dump/restore records of `events_horizon` table. `events_horizon` table is used to supply subscriptions functionality and contains temporary data which is scoped to the PostgreSQL cluster they were created in. **Thus, it is even may be harmful if you restore records from this table into a new PostgreSQL cluster. Simply exclude that table's data when performing backups.** Example:
|
|
63
|
-
|
|
64
|
-
```bash
|
|
65
|
-
pg_dump --exclude-table-data=events_horizon eventstore -U postgres > eventstore.sql
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
Also, it is important you create and migrate new database via provided rake commands - they include an important setup of `pg_cron` jobs as well. **Even if you would like to restore your db backup on clean PostgreSQL instance - please initialize pg_eventstore via built-in tools first.**
|
|
69
|
-
|
|
70
76
|
## RSpec
|
|
71
77
|
|
|
72
78
|
### Clean up test db
|
|
@@ -117,14 +123,18 @@ end
|
|
|
117
123
|
After checking out the repo, run:
|
|
118
124
|
- `bundle` to install dependencies
|
|
119
125
|
- `docker compose up` to start dev/test services
|
|
126
|
+
- `bundle exec rake compile` to compile native extension
|
|
120
127
|
- `bin/setup_db` to create/re-create development and test databases, tables and related objects
|
|
121
128
|
- `bundle exec rbs collection install` to install external rbs definitions
|
|
122
129
|
|
|
123
|
-
Then, run `bin/rspec` to run the tests
|
|
130
|
+
Then, run `bin/rspec` to run the tests(or just `rspec` if you want to temporary skip rbs checks). Optional env variables for testing:
|
|
131
|
+
- `DEBUG=1 bin/rspec`. Enable nicely formatted and highlighted SQL output into stdout.
|
|
132
|
+
|
|
133
|
+
You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
|
124
134
|
|
|
125
135
|
To install this gem onto your local machine, run `bundle exec rake install`.
|
|
126
136
|
|
|
127
|
-
To run admin UI web server - run `puma` in your terminal. By default it will start web server on `http://0.0.0.0:9292`.
|
|
137
|
+
To run admin UI web server - run `puma` in your terminal. By default, it will start web server on `http://0.0.0.0:9292`.
|
|
128
138
|
|
|
129
139
|
### Benchmarks
|
|
130
140
|
|
|
@@ -1,23 +1 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
PgEventstore.connection(:_postgres_db_connection).with do |conn|
|
|
4
|
-
conn.exec(<<~SQL)
|
|
5
|
-
CREATE EXTENSION IF NOT EXISTS pg_cron
|
|
6
|
-
SQL
|
|
7
|
-
conn.exec_params(<<~SQL, ["prune_#{PgEventstore::MigrationHelpers.db_name}_events_horizon", PgEventstore::MigrationHelpers.db_name])
|
|
8
|
-
SELECT cron.schedule_in_database(
|
|
9
|
-
$1,
|
|
10
|
-
'*/10 * * * *',
|
|
11
|
-
$$DELETE FROM events_horizon WHERE xact_id <= (SELECT xact_id FROM events_horizon ORDER BY xact_id DESC OFFSET 100 LIMIT 1)$$,
|
|
12
|
-
$2
|
|
13
|
-
)
|
|
14
|
-
SQL
|
|
15
|
-
# Store information about finished cron jobs for 1 day
|
|
16
|
-
conn.exec(<<~SQL)
|
|
17
|
-
SELECT cron.schedule(
|
|
18
|
-
'delete-job-run-details',
|
|
19
|
-
'0 12 * * *',
|
|
20
|
-
$$DELETE FROM cron.job_run_details WHERE end_time < now() - interval '1 day'$$
|
|
21
|
-
);
|
|
22
|
-
SQL
|
|
23
|
-
end
|
|
1
|
+
# pg_cron was removed. This file is kept for informative purpose.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
CREATE TABLE public.streams_global_index
|
|
2
|
+
(
|
|
3
|
+
id bigserial NOT NULL,
|
|
4
|
+
partition_id bigint NOT NULL,
|
|
5
|
+
stream_id character varying COLLATE "POSIX" NOT NULL,
|
|
6
|
+
stream_revision bigint NOT NULL,
|
|
7
|
+
starting_position bigint NOT NULL
|
|
8
|
+
);
|
|
9
|
+
|
|
10
|
+
ALTER TABLE ONLY public.streams_global_index
|
|
11
|
+
ADD CONSTRAINT streams_global_index_pkey PRIMARY KEY (id);
|
|
12
|
+
|
|
13
|
+
CREATE UNIQUE INDEX idx_streams_global_index_on_stream_id_and_partition_id ON public.streams_global_index
|
|
14
|
+
USING btree (stream_id, partition_id) INCLUDE (id);
|
|
15
|
+
|
|
16
|
+
CREATE INDEX idx_streams_global_index_on_starting_position ON public.streams_global_index
|
|
17
|
+
USING btree (starting_position);
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
CONCURRENCY = ENV['CONCURRENCY']&.to_i || 10
|
|
4
|
+
|
|
5
|
+
PgEventstore.configure(name: :_eventstore_db_connection) do |config|
|
|
6
|
+
config.connection_pool_size = CONCURRENCY * 10
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
partitions = PgEventstore.connection(:_eventstore_db_connection).with do |conn|
|
|
10
|
+
conn.exec('select * from partitions where event_type is null')
|
|
11
|
+
end.to_a
|
|
12
|
+
|
|
13
|
+
stream_name_partitions = partitions.reject { _1['stream_name'].nil? }.group_by { _1['context'] }
|
|
14
|
+
stream_name_partitions = stream_name_partitions.to_h do |context, context_parts|
|
|
15
|
+
context_parts = context_parts.to_h { |p| [p['stream_name'], p['id']] }
|
|
16
|
+
[context, context_parts]
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
total_streams = PgEventstore.connection(:_eventstore_db_connection).with do |conn|
|
|
20
|
+
conn.exec('explain select * from "$streams"')
|
|
21
|
+
end.first['QUERY PLAN'][/rows=\d+/].sub('rows=', '').to_i
|
|
22
|
+
|
|
23
|
+
tables = PgEventstore.connection(:_eventstore_db_connection).with do |conn|
|
|
24
|
+
conn.exec('select table_name from partitions where event_type is not null')
|
|
25
|
+
end.to_a.map { _1['table_name'] }
|
|
26
|
+
|
|
27
|
+
PgEventstore.connection(:_eventstore_db_connection).with do |conn|
|
|
28
|
+
conn.exec('delete from streams_global_index')
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
puts "Indexing streams. Approximate number of streams to process: #{total_streams}. Concurrency is #{CONCURRENCY} concurrent writers."
|
|
32
|
+
puts <<~TEXT
|
|
33
|
+
This migration consumes CONCURRENCY x10 connections. Make sure you have plenty of them. Migrations are idempotent, \
|
|
34
|
+
so you can break, adjust settings if needed and then start over.
|
|
35
|
+
TEXT
|
|
36
|
+
puts
|
|
37
|
+
|
|
38
|
+
processed = 0
|
|
39
|
+
processed_was = 0
|
|
40
|
+
time = Time.now
|
|
41
|
+
lock = Thread::Mutex.new
|
|
42
|
+
sub_partitions_count_cache = {}
|
|
43
|
+
threads = CONCURRENCY.times.map do |t|
|
|
44
|
+
Thread.new do
|
|
45
|
+
tables.each do |table|
|
|
46
|
+
global_position = 0
|
|
47
|
+
loop do
|
|
48
|
+
events = PgEventstore.connection(:_eventstore_db_connection).with do |conn|
|
|
49
|
+
conn.exec_params(<<~SQL, [global_position, CONCURRENCY, t])
|
|
50
|
+
select context, stream_name, stream_id, global_position
|
|
51
|
+
from "#{table}"
|
|
52
|
+
where global_position > $1 and global_position % $2 = $3 and stream_revision = 0
|
|
53
|
+
group by context, stream_name, stream_id, global_position
|
|
54
|
+
order by global_position asc
|
|
55
|
+
limit 100
|
|
56
|
+
SQL
|
|
57
|
+
end.to_a
|
|
58
|
+
break if events.empty?
|
|
59
|
+
|
|
60
|
+
global_position = events.last['global_position']
|
|
61
|
+
|
|
62
|
+
# retrieve stream revision
|
|
63
|
+
events.each_slice(10) do |sliced_events|
|
|
64
|
+
query_runner = PgEventstore::AsyncRunner.new
|
|
65
|
+
sliced_events.each do |event|
|
|
66
|
+
query_runner.async do
|
|
67
|
+
query_strategy = PgEventstore::QueryStrategy::Async.new(PgEventstore.connection(:_eventstore_db_connection))
|
|
68
|
+
context = event['context']
|
|
69
|
+
stream_name = event['stream_name']
|
|
70
|
+
stream_id = event['stream_id']
|
|
71
|
+
sub_partitions_count_cache[[context, stream_name]] ||= query_strategy.exec_params(
|
|
72
|
+
'select count(*) as c_all from partitions where context = $1 and stream_name = $2',
|
|
73
|
+
[context, stream_name]
|
|
74
|
+
).first['c_all']
|
|
75
|
+
if sub_partitions_count_cache[[context, stream_name]] > 50
|
|
76
|
+
sub_partitions = query_strategy.exec_params(<<~SQL, [context, stream_name]).map { _1['table_name'] }
|
|
77
|
+
select table_name from partitions where context = $1 and stream_name = $2 and event_type is not null
|
|
78
|
+
SQL
|
|
79
|
+
max_revisions = []
|
|
80
|
+
sub_partitions.each_slice(50) do |table_names|
|
|
81
|
+
q_parts = table_names.map do |table_name|
|
|
82
|
+
<<~SQL
|
|
83
|
+
select max(stream_revision) as stream_revision
|
|
84
|
+
from #{table_name}
|
|
85
|
+
where context = $1 and stream_name = $2 and stream_id = $3
|
|
86
|
+
SQL
|
|
87
|
+
end
|
|
88
|
+
q_parts = q_parts.map { "(#{_1})" }.join(' union all ')
|
|
89
|
+
q = "select coalesce(max(stream_revision), -1) as stream_revision from (#{q_parts})"
|
|
90
|
+
max_revisions.push(
|
|
91
|
+
query_strategy.exec_params(q, [context, stream_name, stream_id]).first['stream_revision']
|
|
92
|
+
)
|
|
93
|
+
end
|
|
94
|
+
event['stream_revision'] = max_revisions.max
|
|
95
|
+
else
|
|
96
|
+
q = <<~SQL
|
|
97
|
+
select max(stream_revision) as stream_revision
|
|
98
|
+
from events
|
|
99
|
+
where context = $1 and stream_name = $2 and stream_id = $3
|
|
100
|
+
SQL
|
|
101
|
+
attrs = query_strategy.exec_params(q, [context, stream_name, stream_id]).to_a.first
|
|
102
|
+
event['stream_revision'] = attrs['stream_revision']
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
query_runner.run
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
values = events.map do |event|
|
|
110
|
+
partition_id = stream_name_partitions[event['context']][event['stream_name']]
|
|
111
|
+
stream_id = PG::Connection.escape(event['stream_id'])
|
|
112
|
+
stream_revision = event['stream_revision']
|
|
113
|
+
starting_position = event['global_position']
|
|
114
|
+
"(#{partition_id}, '#{stream_id}', #{stream_revision}, #{starting_position})"
|
|
115
|
+
end.join(',')
|
|
116
|
+
|
|
117
|
+
PgEventstore.connection(:_eventstore_db_connection).with do |conn|
|
|
118
|
+
conn.exec(<<~SQL)
|
|
119
|
+
INSERT INTO streams_global_index
|
|
120
|
+
("partition_id", "stream_id", "stream_revision", "starting_position")
|
|
121
|
+
VALUES #{values}
|
|
122
|
+
SQL
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
lock.synchronize do
|
|
126
|
+
processed += events.size
|
|
127
|
+
next if Time.now - time < 2
|
|
128
|
+
|
|
129
|
+
time_was = time
|
|
130
|
+
time = Time.now
|
|
131
|
+
|
|
132
|
+
performance_info = <<~TEXT.strip
|
|
133
|
+
Processed: #{processed}. Left: #{total_streams - processed} (approximately). \
|
|
134
|
+
Performance: #{((processed - processed_was) / (time - time_was)).round(2)} streams/second.
|
|
135
|
+
TEXT
|
|
136
|
+
processed_was = processed
|
|
137
|
+
print "#{performance_info} \r"
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
threads.each(&:join)
|
|
144
|
+
|
|
145
|
+
PgEventstore.connection(:_eventstore_db_connection).with do |conn|
|
|
146
|
+
puts 'Running cluster on streams_global_index. This may take some time.'
|
|
147
|
+
conn.exec('CLUSTER streams_global_index USING idx_streams_global_index_on_starting_position')
|
|
148
|
+
puts 'Running vacuum on streams_global_index. This may take some time.'
|
|
149
|
+
conn.exec('VACUUM (ANALYZE) streams_global_index')
|
|
150
|
+
end
|