pg_eventstore 2.0.0 → 3.0.1
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 +190 -20
- data/README.md +27 -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 +98 -36
- data/docs/event_tracing.md +55 -0
- data/docs/events_and_streams.md +54 -30
- data/docs/how_it_works.md +41 -25
- 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: 24899ca6d10bac21341f41f3a8cfee09e10ce10bf81fb4525e9660f6c708d3af
|
|
4
|
+
data.tar.gz: 07cbbca86a3cb488d9123d663e77cb66cdbf850f93e12f1f15e46dc8f465879c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: bc33cc4bcdda545ffa4476e80b55ca2541de4da036d715644f3957d1889170bbdf3b05b1391c7f981f28163da0ce36d06b0a8282ddeddb7560eb1892df43cfaa
|
|
7
|
+
data.tar.gz: 64b63413791d2c993315d4012acb1a5bec19b237eae6761c6b9da8725483e4284f5fbf3b956df5c4a750719460087f30cec6c9db1f176ce728ad985f2aefa213
|
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,145 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [3.0.1]
|
|
4
|
+
|
|
5
|
+
- Fix EventTracing bug: Respect user-supplied Event#correlation_id value when caused_by#correlation_id is absent
|
|
6
|
+
|
|
7
|
+
## [3.0.0]
|
|
8
|
+
|
|
9
|
+
- New feature: pg_eventstore replication
|
|
10
|
+
- **Breaking change**: drop support of Ruby v3.2. The gem now requires Ruby v3.3+
|
|
11
|
+
- New feature: event tracing. You can now configure pg_eventstore to trace causation dependencies of events.
|
|
12
|
+
Read more [here](docs/event_tracing.md)
|
|
13
|
+
- **Breaking change**: when event is persisted using `#append_to_stream` - it now gets deserialized via each registered
|
|
14
|
+
middleware by default. Previously this wasn't the case - the deserialization phase was skipped. Such behavior was
|
|
15
|
+
creating ambiguity about assumptions when deserialization happens. If you need old behavior - you have to create
|
|
16
|
+
another middleware class which skips deserialization when publishing events and use it instead. Example:
|
|
17
|
+
Let's say you have this middleware configured
|
|
18
|
+
```ruby
|
|
19
|
+
class MyMiddleware
|
|
20
|
+
include PgEventstore::Middleware
|
|
21
|
+
|
|
22
|
+
def serialize(event)
|
|
23
|
+
# do something with event before persisting it
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def deserialize(event)
|
|
27
|
+
# do something with event after reading it from db
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
PgEventstore.configure do |config|
|
|
32
|
+
config.middleware = { my_middleware: MyMiddleware.new }
|
|
33
|
+
end
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Now define another middleware that has empty `#deserialize` method
|
|
37
|
+
|
|
38
|
+
```ruby
|
|
39
|
+
class MyMiddlewareWithoutDeserialize < MyMiddleware
|
|
40
|
+
def deserialize(event)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
PgEventstore.configure do |config|
|
|
45
|
+
config.middleware = {
|
|
46
|
+
my_middleware: MyMiddleware.new,
|
|
47
|
+
my_middleware_wo_deserialize: MyMiddlewareWithoutDeserialize.new
|
|
48
|
+
}
|
|
49
|
+
end
|
|
50
|
+
```
|
|
51
|
+
and use only it when publishing events:
|
|
52
|
+
|
|
53
|
+
```ruby
|
|
54
|
+
PgEventstore.client.append_to_stream(stream, event, middlewares: [:my_middleware_wo_deserialize])
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Alternatively, if you don't rely on `#multiple`, you can create another config specially for write operations:
|
|
58
|
+
|
|
59
|
+
```ruby
|
|
60
|
+
# this is your default
|
|
61
|
+
PgEventstore.configure do |config|
|
|
62
|
+
config.middleware = { my_middleware: MyMiddleware.new }
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
PgEventstore.configure(name: :write) do |config|
|
|
66
|
+
config.middleware = { my_middleware: MyMiddlewareWithoutDeserialize.new }
|
|
67
|
+
end
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
and use it for write operations:
|
|
71
|
+
|
|
72
|
+
```ruby
|
|
73
|
+
PgEventstore.client(:write).append_to_stream(stream, event)
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
- **Breaking change**: `Event#id` uniqueness is no longer guaranteed. It was dropped because there is not much usage of
|
|
77
|
+
it internally. The default value was moved from the database(it was `gen_random_uuid()`) to the application level and
|
|
78
|
+
is `SecureRandom.uuid_v7` now.
|
|
79
|
+
- **Breaking change**: event types, stream attributes, event metadata keys, markers that start from `▒`(`"\u2592"`
|
|
80
|
+
Unicode character) character are now reserved by pg_eventstore. It is less likely you have any, but if you do - you have
|
|
81
|
+
to adjust your implementation to no longer rely on it.
|
|
82
|
+
- New feature: event markers. You can now mark an event and later use those markers to read events, build a projection
|
|
83
|
+
using subscriptions or validate stream revision scoped to an event type and specific markers when publishing events as
|
|
84
|
+
a part of Dynamic Consistency Boundaries. Find more in [docs](docs/appending_events.md#event-markers)
|
|
85
|
+
- New config option `config.events_subscription_position_update_interval`. See more
|
|
86
|
+
in [Configuration](docs/configuration.md) docs
|
|
87
|
+
- **Breaking change**: `:from_position` option of `SubscriptionManager#subscribe`, "Current position" column in admin
|
|
88
|
+
web UI, "Reset position" form in admin web UI now refers to the event subscription position instead
|
|
89
|
+
`Event#global_position`. See more information in related
|
|
90
|
+
docs [Subscription position](docs/subscriptions.md#subscription-position)
|
|
91
|
+
- **Breaking change**: Drop `pg_cron` dependency
|
|
92
|
+
- Remove deprecated `SubscriptionsManager#force_lock!`
|
|
93
|
+
- New feature: explicit support of Dynamic Consistency Boundaries when publishing events. You can now provide "event
|
|
94
|
+
type"-to-"expected stream revision" hash map into `:expected_revision` option. It allows to validate against stream
|
|
95
|
+
revision at the specific event type instead validating the whole stream. Example:
|
|
96
|
+
`PgEventstore.client.append_to_stream(stream, events, options: { expected_revision: { 'Foo' => 10, 'Bar' => 20 } })`
|
|
97
|
+
- **Breaking change**: `WrongExpectedRevisionError#new` now requires `:verdict` keyword argument.
|
|
98
|
+
`Client#append_to_stream` now also may raise `WrongExpectedTypesRevisionError` error in case `:expected_revision`
|
|
99
|
+
option is "event type"-to-"expected stream revision" hash map
|
|
100
|
+
- Remove any practical limit of `Event#stream_revision` by changing its type to `bigint`. Stream size can be practically
|
|
101
|
+
unreachable now
|
|
102
|
+
- Fix issue when incomplete transaction block may be interrupted half way and commited successfully. The issue is
|
|
103
|
+
related to incorrect transaction termination flow during non-graceful thread shutdown(e.g. via `Thread.exit`)
|
|
104
|
+
- New feature: `Client#stream_revision` allows to quickly get stream's revision. Example:
|
|
105
|
+
`PgEventstore.client.stream_revision(stream) #=> number, greater than or equal to 0 or -1 if stream does not exist`
|
|
106
|
+
- **Breaking change**: `Client#read_grouped` now requires to provide `event_types` filter option explicitly. Example:
|
|
107
|
+
`PgEventstore.client.read_grouped(stream, options: { filter: { event_types: ['Foo', 'Bar'] } })`
|
|
108
|
+
- New feature: Subscription event types filter now support prefixes. So, if you have subscriptions like
|
|
109
|
+
`manager.subscribe('MyAwesomeSubscription', handler: my_handler, options: { filter: { event_types: ['Foo1', 'Foo2', 'Foo3'] } })`,
|
|
110
|
+
you can replace its filter as follows: `{ event_types: [{ prefix: 'Foo' }] }`. **Read API does not support this
|
|
111
|
+
feature yet**
|
|
112
|
+
- New feature: Read API now supports `:to_position`(and `:to_revision` when reading from specific stream) option. Use it
|
|
113
|
+
if you want to limit your result alongside `:max_count` option. Example:
|
|
114
|
+
`PgEventstore.client.read(PgEventstore::Stream.all_stream, options: { from_position: 100, to_position: 200 })`
|
|
115
|
+
- **Breaking change**: `Middleware#serialize` is now called outside SQL transaction that inserts an event tuple.
|
|
116
|
+
Previously it was happening right before an `INSERT` statement
|
|
117
|
+
- **Breaking change**: Database structure and the implementation of `#append_to_stream` was changed in a way it is not
|
|
118
|
+
compatible with v2. Public API stays the same
|
|
119
|
+
- New feature: allow subscription to process events in batches. You can now provide `in_batches: true` to `#subscribe`
|
|
120
|
+
to yield an array of events. See [docs](docs/subscriptions.md#processing-events-in-batches) for more info
|
|
121
|
+
- Introduce `PgEventstore::BasicConfig` and `PgEventstore::Extensions::ActsAsConfigurable` to allow to easily create
|
|
122
|
+
configurable objects
|
|
123
|
+
|
|
3
124
|
## [2.0.0]
|
|
4
125
|
|
|
5
126
|
- **Breaking change**: `pg_eventstore` now requires [pg_cron](https://github.com/citusdata/pg_cron) extension
|
|
6
127
|
- **Breaking change**: `pg_eventstore` now requires PostgreSQL v16+
|
|
7
128
|
- Greatly decreased the number of connections, used by `pg_eventstore` subscriptions
|
|
8
129
|
- **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 -
|
|
130
|
+
- **Breaking change**: `PgEventstore::Extensions::OptionsExtension::Options` class is no longer a child of `Set` class -
|
|
131
|
+
it has independent implementation now
|
|
10
132
|
- 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
|
-
-
|
|
133
|
+
- `Client#multiple` method now accepts `read_only` keyword argument. When it is set to true - transaction is run in
|
|
134
|
+
read-only mode
|
|
135
|
+
- **Breaking change**: rework links implementation. This change boosts performance, but affects the database structure,
|
|
136
|
+
so your previous database dumps become incompatible with this change. `PgEventstore::Event#link_id` was replaced by
|
|
137
|
+
`PgEventstore::Event#link_global_position`
|
|
13
138
|
|
|
14
|
-
Changes above require you to run migrations - `bundle exec rake pg_eventstore:migrate`. One of the migrations also
|
|
139
|
+
Changes above require you to run migrations - `bundle exec rake pg_eventstore:migrate`. One of the migrations also
|
|
140
|
+
migrates existing data using several concurrent workers(threads). You can adjust the number of workers using
|
|
141
|
+
`CONCURRENCY` environment variable. Default number of concurrent workers is `10`. **Migrations require a downtime - no
|
|
142
|
+
reads/writes should be performed during the time of the migrations, so plan your maintenance downtime accordingly.**
|
|
15
143
|
|
|
16
144
|
## [1.13.4]
|
|
17
145
|
|
|
@@ -31,7 +159,8 @@ Changes above require you to run migrations - `bundle exec rake pg_eventstore:mi
|
|
|
31
159
|
|
|
32
160
|
## [1.13.0]
|
|
33
161
|
|
|
34
|
-
- Introduce automatic subscriptions recovery from connection errors. This way if a subscription process loses the
|
|
162
|
+
- Introduce automatic subscriptions recovery from connection errors. This way if a subscription process loses the
|
|
163
|
+
connection to the database - it will be trying to reconnect until the connection is restored.
|
|
35
164
|
- Resolve ambiguity in usage of `PgEventstore.config` method. It now returns the frozen object.
|
|
36
165
|
|
|
37
166
|
## [1.12.0]
|
|
@@ -40,12 +169,17 @@ Changes above require you to run migrations - `bundle exec rake pg_eventstore:mi
|
|
|
40
169
|
|
|
41
170
|
## [1.11.0]
|
|
42
171
|
|
|
43
|
-
- Add a global position that caused an error to the subscription's error JSON info. This will help you understand what
|
|
172
|
+
- Add a global position that caused an error to the subscription's error JSON info. This will help you understand what
|
|
173
|
+
event caused your subscription to fail.
|
|
44
174
|
- 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
|
|
175
|
+
- Admin UI: adjust events filtering and displaying of stream context, stream name, stream id and event type when values
|
|
176
|
+
of them contain empty strings or non-displayable characters
|
|
46
177
|
|
|
47
178
|
## [1.10.0]
|
|
48
|
-
|
|
179
|
+
|
|
180
|
+
- Admin UI: Adjust `SubscriptionSet` "Stop"/"Delete" buttons appearance. Now if `SubscriptionsSet` is not alive anymore(
|
|
181
|
+
the related process is dead or does not exist anymore) - "Delete" button is shown. If `SubscriptionSet` is alive - "
|
|
182
|
+
Stop" button is shown
|
|
49
183
|
- Admin IU: fixed several potential XSS vulnerabilities
|
|
50
184
|
- Admin IU: Add "Copy to clipboard" button near stream id that copies ruby stream definition
|
|
51
185
|
- Admin UI: allow deletion of streams with empty attribute values
|
|
@@ -57,23 +191,33 @@ Changes above require you to run migrations - `bundle exec rake pg_eventstore:mi
|
|
|
57
191
|
- Add "Delete event" and "Delete stream" buttons into admin UI
|
|
58
192
|
|
|
59
193
|
## [1.8.0]
|
|
60
|
-
|
|
194
|
+
|
|
195
|
+
- Introduce default config for admin web UI. Now if you define `:admin_web_ui` config - it will be preferred over
|
|
196
|
+
default config
|
|
61
197
|
- Fix pagination of events in admin UI
|
|
62
198
|
- Improve partial index for `$streams` system stream
|
|
63
199
|
|
|
64
200
|
## [1.7.0]
|
|
201
|
+
|
|
65
202
|
- Implement reading from `"$streams"` system stream
|
|
66
203
|
- Disable Host authorization introduced in sinatra v4.1
|
|
67
204
|
|
|
68
205
|
## [1.6.0]
|
|
69
|
-
|
|
206
|
+
|
|
207
|
+
- Introduce subscriptions CLI. Type `pg-eventstore subscriptions --help` to see available commands. The main purpose of
|
|
208
|
+
it is to provide the single way to start/stop subscription processes.
|
|
209
|
+
Check [Subscriptions](docs/subscriptions.md#creating-a-subscription) docs about the new way to start and keep running
|
|
210
|
+
a subscriptions process.
|
|
70
211
|
|
|
71
212
|
## [1.5.0]
|
|
213
|
+
|
|
72
214
|
- Add ability to toggle link events in the admin UI
|
|
73
215
|
- Mark linked events in the admin UI with "link" icon
|
|
74
216
|
|
|
75
217
|
## [1.4.0]
|
|
76
|
-
|
|
218
|
+
|
|
219
|
+
- Add an ability to configure subscription graceful shutdown timeout globally and per subscription. Default value is 15
|
|
220
|
+
seconds. Previously it was hardcoded to 5 seconds. Examples:
|
|
77
221
|
|
|
78
222
|
```ruby
|
|
79
223
|
# Set it globally, for all subscriptions
|
|
@@ -90,18 +234,24 @@ subscriptions_manager.subscribe(
|
|
|
90
234
|
```
|
|
91
235
|
|
|
92
236
|
## [1.3.4]
|
|
93
|
-
|
|
237
|
+
|
|
238
|
+
- Fix `NoMethodError` error in `Client#read_paginated` when stream does not exist or when there are no events matching
|
|
239
|
+
the given filter
|
|
94
240
|
|
|
95
241
|
## [1.3.3]
|
|
242
|
+
|
|
96
243
|
- Adjust default value of `subscription_max_retries` setting
|
|
97
244
|
|
|
98
245
|
## [1.3.2]
|
|
246
|
+
|
|
99
247
|
- Fix UI when switching subscription status
|
|
100
248
|
|
|
101
249
|
## [1.3.1]
|
|
250
|
+
|
|
102
251
|
- Swap "Search" button and "Add filter" button on Dashboard page
|
|
103
252
|
|
|
104
253
|
## [1.3.0]
|
|
254
|
+
|
|
105
255
|
- Add ability to filter subscriptions by state in admin UI
|
|
106
256
|
- Reset error-related subscription's attributes on subscription restore
|
|
107
257
|
- Reset total processed events number when user changes subscription's position
|
|
@@ -109,9 +259,12 @@ subscriptions_manager.subscribe(
|
|
|
109
259
|
- Relax sinatra version requirement to v3+
|
|
110
260
|
|
|
111
261
|
## [1.2.0]
|
|
262
|
+
|
|
112
263
|
- Implement `failed_subscription_notifier` subscription hook.
|
|
113
264
|
|
|
114
|
-
Now you are able to define a function that is called when subscription fails and no longer can be automatically
|
|
265
|
+
Now you are able to define a function that is called when subscription fails and no longer can be automatically
|
|
266
|
+
restarted because it hit max number of retries. You can define the hook globally in the config and per subscription.
|
|
267
|
+
Examples:
|
|
115
268
|
|
|
116
269
|
```ruby
|
|
117
270
|
PgEventstore.configure do |config|
|
|
@@ -135,36 +288,48 @@ subscriptions_manager.subscribe(
|
|
|
135
288
|
```
|
|
136
289
|
|
|
137
290
|
## [1.1.5]
|
|
138
|
-
|
|
291
|
+
|
|
292
|
+
- Review the way to handle SubscriptionAlreadyLockedError error. This removes noise when attempting to lock an already
|
|
293
|
+
locked subscription.
|
|
139
294
|
|
|
140
295
|
## [1.1.4]
|
|
296
|
+
|
|
141
297
|
- Add rbs signatures
|
|
142
298
|
|
|
143
299
|
## [1.1.3]
|
|
300
|
+
|
|
144
301
|
- Fix issue with assets caching between different gem's versions
|
|
145
302
|
|
|
146
303
|
## [1.1.2]
|
|
304
|
+
|
|
147
305
|
- Improve web app compatibility with rails
|
|
148
306
|
|
|
149
307
|
## [1.1.1]
|
|
308
|
+
|
|
150
309
|
- Allow case insensitive search by context, stream name and event type in admin UI
|
|
151
310
|
|
|
152
311
|
## [1.1.0]
|
|
312
|
+
|
|
153
313
|
- Add "Reset position" button on Subscriptions Admin UI page
|
|
154
314
|
|
|
155
|
-
**Note** This release includes a migration to support new functional. Please don't forget to run
|
|
315
|
+
**Note** This release includes a migration to support new functional. Please don't forget to run
|
|
316
|
+
`rake pg_eventstore:migrate` to apply latest db changes.
|
|
156
317
|
|
|
157
318
|
## [1.0.4]
|
|
319
|
+
|
|
158
320
|
- Fix bug which caused slow Subscriptions to stop processing new events
|
|
159
321
|
- Optimize Subscriptions update queries
|
|
160
322
|
|
|
161
323
|
## [1.0.3]
|
|
324
|
+
|
|
162
325
|
- Do no update `Subscription#last_chunk_fed_at` if the chunk is empty
|
|
163
326
|
|
|
164
327
|
## [1.0.2]
|
|
328
|
+
|
|
165
329
|
- UI: Fix opening of SubscriptionsSet tab of non-existing SubscriptionsSet
|
|
166
330
|
|
|
167
331
|
## [1.0.1]
|
|
332
|
+
|
|
168
333
|
- Adjust assets urls to correctly act when mounting sinatra app under non-root url
|
|
169
334
|
|
|
170
335
|
## [1.0.0]
|
|
@@ -202,7 +367,8 @@ subscriptions_manager.subscribe(
|
|
|
202
367
|
|
|
203
368
|
## [0.8.0] - 2024-02-20
|
|
204
369
|
|
|
205
|
-
- Allow float values for `subscription_pull_interval`. The default value of it was also set to `1.0`(it was `2`
|
|
370
|
+
- Allow float values for `subscription_pull_interval`. The default value of it was also set to `1.0`(it was `2`
|
|
371
|
+
previously)
|
|
206
372
|
|
|
207
373
|
## [0.7.2] - 2024-02-14
|
|
208
374
|
|
|
@@ -214,7 +380,8 @@ subscriptions_manager.subscribe(
|
|
|
214
380
|
|
|
215
381
|
## [0.7.0] - 2024-02-09
|
|
216
382
|
|
|
217
|
-
- Refactor `pg_eventstore:create` and `pg_eventstore:drop` rake tasks. They now actually create/drop the database. You
|
|
383
|
+
- Refactor `pg_eventstore:create` and `pg_eventstore:drop` rake tasks. They now actually create/drop the database. You
|
|
384
|
+
will have to execute `delete from migrations where number > 6` query before deploying this version.
|
|
218
385
|
- Drop legacy migrations
|
|
219
386
|
|
|
220
387
|
## [0.6.0] - 2024-02-08
|
|
@@ -259,9 +426,11 @@ subscriptions_manager.subscribe(
|
|
|
259
426
|
|
|
260
427
|
## [0.2.4] - 2023-12-20
|
|
261
428
|
|
|
262
|
-
Due to performance issues under certain circumstances, searching by event type was giving bad performance. I decided to
|
|
429
|
+
Due to performance issues under certain circumstances, searching by event type was giving bad performance. I decided to
|
|
430
|
+
extract `type` column from `events` table into separated table. **No breaking changes in public API though.**
|
|
263
431
|
|
|
264
|
-
**Warning** The migrations this version has, requires you to shut down applications that use `pg_eventstore` and only
|
|
432
|
+
**Warning** The migrations this version has, requires you to shut down applications that use `pg_eventstore` and only
|
|
433
|
+
then run `rake pg_eventstore:migrate`.
|
|
265
434
|
|
|
266
435
|
## [0.2.3] - 2023-12-18
|
|
267
436
|
|
|
@@ -273,7 +442,8 @@ Due to performance issues under certain circumstances, searching by event type w
|
|
|
273
442
|
|
|
274
443
|
## [0.2.1] - 2023-12-14
|
|
275
444
|
|
|
276
|
-
Under certain circumstances `PG::TRSerializationFailure` exception wasn't retried. Adjust connection's states list to
|
|
445
|
+
Under certain circumstances `PG::TRSerializationFailure` exception wasn't retried. Adjust connection's states list to
|
|
446
|
+
fix that.
|
|
277
447
|
|
|
278
448
|
## [0.2.0] - 2023-12-14
|
|
279
449
|
|
data/README.md
CHANGED
|
@@ -4,11 +4,23 @@ 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
|
+
v3 introduces several new tables to support the functional. Make sure you have enough disk space on your PostgreSQL host.
|
|
16
|
+
|
|
17
|
+
If you are migrating from v2 - please don't forget to delete cron jobs and `pg_cron` extension after migration to v3.
|
|
18
|
+
You can remove cron jobs as follows:
|
|
19
|
+
|
|
20
|
+
```sql
|
|
21
|
+
SELECT cron.unschedule('prune_eventstore_events_horizon');
|
|
22
|
+
SELECT cron.unschedule('delete-job-run-details');
|
|
23
|
+
```
|
|
12
24
|
|
|
13
25
|
## Installation
|
|
14
26
|
|
|
@@ -47,26 +59,22 @@ Documentation chapters:
|
|
|
47
59
|
- [Appending events](docs/appending_events.md)
|
|
48
60
|
- [Linking events](docs/linking_events.md)
|
|
49
61
|
- [Reading events](docs/reading_events.md)
|
|
62
|
+
- [Reading streams](docs/reading_streams.md)
|
|
63
|
+
- [Tracing events](docs/event_tracing.md)
|
|
50
64
|
- [Subscriptions](docs/subscriptions.md)
|
|
51
65
|
- [Maintenance functions](docs/maintenance.md)
|
|
52
66
|
- [Writing middlewares](docs/writing_middleware.md)
|
|
53
67
|
- [How to make multiple commands atomic](docs/multiple_commands.md)
|
|
54
68
|
- [Admin UI](docs/admin_ui.md)
|
|
69
|
+
- [Replication](docs/replication.md)
|
|
70
|
+
|
|
71
|
+
To help your AI assistant to better recognize the capabilities of this gem - there is a crafted [instructions](docs/AGENTS.fragment.md)
|
|
72
|
+
you can include into your `AGENTS.md`.
|
|
55
73
|
|
|
56
74
|
## CLI
|
|
57
75
|
|
|
58
76
|
The gem is shipped with its own CLI. Use `pg-eventstore --help` to find out its capabilities.
|
|
59
77
|
|
|
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
78
|
## RSpec
|
|
71
79
|
|
|
72
80
|
### Clean up test db
|
|
@@ -117,14 +125,18 @@ end
|
|
|
117
125
|
After checking out the repo, run:
|
|
118
126
|
- `bundle` to install dependencies
|
|
119
127
|
- `docker compose up` to start dev/test services
|
|
128
|
+
- `bundle exec rake compile` to compile native extension
|
|
120
129
|
- `bin/setup_db` to create/re-create development and test databases, tables and related objects
|
|
121
130
|
- `bundle exec rbs collection install` to install external rbs definitions
|
|
122
131
|
|
|
123
|
-
Then, run `bin/rspec` to run the tests
|
|
132
|
+
Then, run `bin/rspec` to run the tests(or just `rspec` if you want to temporary skip rbs checks). Optional env variables for testing:
|
|
133
|
+
- `DEBUG=1 bin/rspec`. Enable nicely formatted and highlighted SQL output into stdout.
|
|
134
|
+
|
|
135
|
+
You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
|
124
136
|
|
|
125
137
|
To install this gem onto your local machine, run `bundle exec rake install`.
|
|
126
138
|
|
|
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`.
|
|
139
|
+
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
140
|
|
|
129
141
|
### Benchmarks
|
|
130
142
|
|
|
@@ -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
|