pg_eventstore 1.4.0 → 1.5.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.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +4 -0
  3. data/lib/pg_eventstore/extensions/callback_handlers_extension.rb +21 -0
  4. data/lib/pg_eventstore/subscriptions/callback_handlers/commands_handler_handlers.rb +38 -0
  5. data/lib/pg_eventstore/subscriptions/callback_handlers/events_processor_handlers.rb +45 -0
  6. data/lib/pg_eventstore/subscriptions/callback_handlers/subscription_feeder_handlers.rb +103 -0
  7. data/lib/pg_eventstore/subscriptions/callback_handlers/subscription_runner_handlers.rb +75 -0
  8. data/lib/pg_eventstore/subscriptions/commands_handler.rb +13 -29
  9. data/lib/pg_eventstore/subscriptions/events_processor.rb +17 -41
  10. data/lib/pg_eventstore/subscriptions/subscription_feeder.rb +77 -125
  11. data/lib/pg_eventstore/subscriptions/subscription_runner.rb +30 -55
  12. data/lib/pg_eventstore/subscriptions/subscriptions_lifecycle.rb +70 -0
  13. data/lib/pg_eventstore/subscriptions/subscriptions_manager.rb +8 -2
  14. data/lib/pg_eventstore/subscriptions/subscriptions_set_lifecycle.rb +39 -0
  15. data/lib/pg_eventstore/utils.rb +8 -0
  16. data/lib/pg_eventstore/version.rb +1 -1
  17. data/lib/pg_eventstore/web/application.rb +9 -1
  18. data/lib/pg_eventstore/web/paginator/events_collection.rb +1 -3
  19. data/lib/pg_eventstore/web/paginator/helpers.rb +4 -1
  20. data/lib/pg_eventstore/web/public/javascripts/pg_eventstore.js +10 -1
  21. data/lib/pg_eventstore/web/subscriptions/helpers.rb +3 -4
  22. data/lib/pg_eventstore/web/views/home/dashboard.erb +11 -0
  23. data/lib/pg_eventstore/web/views/home/partials/events.erb +6 -1
  24. data/lib/pg_eventstore/web/views/subscriptions/index.erb +2 -2
  25. data/lib/pg_eventstore.rb +1 -0
  26. data/sig/interfaces/_raw_event_handler.rbs +3 -0
  27. data/sig/pg_eventstore/extensions/callback_handlers_extension.rbs +11 -0
  28. data/sig/pg_eventstore/subscriptions/callback_handlers/commands_handler_handlers.rbs +10 -0
  29. data/sig/pg_eventstore/subscriptions/callback_handlers/events_processor_handlers.rbs +11 -0
  30. data/sig/pg_eventstore/subscriptions/callback_handlers/subscription_feeder_handlers.rbs +31 -0
  31. data/sig/pg_eventstore/subscriptions/callback_handlers/subscription_runner_handlers.rbs +19 -0
  32. data/sig/pg_eventstore/subscriptions/events_processor.rbs +1 -1
  33. data/sig/pg_eventstore/subscriptions/subscription_feeder.rbs +2 -30
  34. data/sig/pg_eventstore/subscriptions/subscriptions_lifecycle.rbs +27 -0
  35. data/sig/pg_eventstore/subscriptions/subscriptions_manager.rbs +1 -1
  36. data/sig/pg_eventstore/subscriptions/subscriptions_set_lifecycle.rbs +24 -0
  37. data/sig/pg_eventstore/utils.rbs +2 -0
  38. data/sig/pg_eventstore/web/subscriptions/helpers.rbs +1 -1
  39. metadata +17 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 80f70b0a0704b224854bda8c4d0a5ffeba9dad355cb44233e84146ece3dcc9fc
4
- data.tar.gz: '0682683f6b68f27dbf9ec88af1804ff82995ebb899c56ea40595b79ab68afe48'
3
+ metadata.gz: ec41b398e1f38d66e73967447ea4f12896ed2cf57eb0dbad8b71acf4257f9cd4
4
+ data.tar.gz: ce571ef411adeeb18b7bae463cac339a053d96f1b36e3de0b1023b8551b03ac5
5
5
  SHA512:
6
- metadata.gz: 47adc4ffc8200caf20e26ce4e436c3f5609e78f378fd1345639c56d39db2af7489a7790e7924c9c4316055771424aae062eb4a55ee3070d82d12f80411aa5198
7
- data.tar.gz: 0b512311767198a395897f27177e2c9e24280d99763f2aa23cd40021d2969c6d0a93886240a3407ea9ef4067f7d26847fe6b349bcab9040df64bf16f4a8058a7
6
+ metadata.gz: 9273a4efb9855d219b1a92b5d9081e3d0d62f9de7f21c48e634949d218ed6a8278d81367f794ee8b70efa64541d7a4442ccf09e7b4cc3bcbd39398f5c7980ec2
7
+ data.tar.gz: ffb85f8c9063aa6e11b8f900e128b4b873e89db117b39e703de6603fc73c014811b63950ff0a0340b0316da11ed2562418f56f1faf42a04491fb0105d913fced
data/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [1.5.0]
4
+ - Add ability to toggle link events in the admin UI
5
+ - Mark linked events in the admin UI with "link" icon
6
+
3
7
  ## [1.4.0]
4
8
  - Add an ability to configure subscription graceful shutdown timeout globally and per subscription. Default value is 15 seconds. Previously it was hardcoded to 5 seconds. Examples:
5
9
 
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PgEventstore
4
+ module Extensions
5
+ module CallbackHandlersExtension
6
+ def self.included(klass)
7
+ klass.extend(ClassMethods)
8
+ end
9
+
10
+ module ClassMethods
11
+ # @param name [Symbol] a name of the handler
12
+ # @return [Proc]
13
+ def setup_handler(name, *args)
14
+ proc do |*rest|
15
+ public_send(name, *args, *rest)
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PgEventstore
4
+ class CommandsHandlerHandlers
5
+ include Extensions::CallbackHandlersExtension
6
+
7
+ class << self
8
+ # @param config_name [Symbol]
9
+ # @param subscription_feeder [PgEventstore::SubscriptionFeeder]
10
+ # @return [void]
11
+ def process_feeder_commands(config_name, subscription_feeder)
12
+ CommandHandlers::SubscriptionFeederCommands.new(config_name, subscription_feeder).process
13
+ end
14
+
15
+ # @param config_name [Symbol]
16
+ # @param runners [Array<PgEventstore::SubscriptionRunner>]
17
+ # @param subscription_feeder [PgEventstore::SubscriptionFeeder]
18
+ # @return [void]
19
+ def process_runners_commands(config_name, runners, subscription_feeder)
20
+ CommandHandlers::SubscriptionRunnersCommands.new(config_name, runners, subscription_feeder.id).process
21
+ end
22
+
23
+ # @param basic_runner [PgEventstore::BasicRunner]
24
+ # @param restart_delay [Integer]
25
+ # @param error [StandardError]
26
+ # @return [void]
27
+ def restore_runner(basic_runner, restart_delay, error)
28
+ PgEventstore.logger&.error "PgEventstore::CommandsHandler: Error occurred: #{error.message}"
29
+ PgEventstore.logger&.error "PgEventstore::CommandsHandler: Backtrace: #{error.backtrace&.join("\n")}"
30
+ PgEventstore.logger&.error "PgEventstore::CommandsHandler: Trying to auto-repair in #{restart_delay} seconds..."
31
+ Thread.new do
32
+ sleep restart_delay
33
+ basic_runner.restore
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PgEventstore
4
+ class EventsProcessorHandlers
5
+ include Extensions::CallbackHandlersExtension
6
+
7
+ class << self
8
+ # @param callbacks [PgEventstore::Callbacks]
9
+ # @param handler [#call]
10
+ # @param raw_events [Array<Hash>]
11
+ # @return [void]
12
+ def process_event(callbacks, handler, raw_events)
13
+ raw_event = raw_events.shift
14
+ return sleep 0.5 if raw_event.nil?
15
+
16
+ callbacks.run_callbacks(:process, Utils.original_global_position(raw_event)) do
17
+ handler.call(raw_event)
18
+ end
19
+ rescue
20
+ raw_events.unshift(raw_event)
21
+ raise
22
+ end
23
+
24
+ # @param callbacks [PgEventstore::Callbacks]
25
+ # @param error [StandardError]
26
+ # @return [void]
27
+ def after_runner_died(callbacks, error)
28
+ callbacks.run_callbacks(:error, error)
29
+ end
30
+
31
+ # @param callbacks [PgEventstore::Callbacks]
32
+ # @return [void]
33
+ def before_runner_restored(callbacks)
34
+ callbacks.run_callbacks(:restart)
35
+ end
36
+
37
+ # @param callbacks [PgEventstore::Callbacks]
38
+ # @param state [String]
39
+ # @return [void]
40
+ def change_state(callbacks, state)
41
+ callbacks.run_callbacks(:change_state, state)
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,103 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PgEventstore
4
+ class SubscriptionFeederHandlers
5
+ include Extensions::CallbackHandlersExtension
6
+
7
+ class << self
8
+ # @param subscriptions_set_lifecycle [PgEventstore::SubscriptionsSetLifecycle]
9
+ # @param state [String]
10
+ # @return [void]
11
+ def update_subscriptions_set_state(subscriptions_set_lifecycle, state)
12
+ subscriptions_set_lifecycle.persisted_subscriptions_set.update(state: state)
13
+ end
14
+
15
+ # @param subscriptions_lifecycle [PgEventstore::SubscriptionsLifecycle]
16
+ # @return [void]
17
+ def lock_subscriptions(subscriptions_lifecycle)
18
+ subscriptions_lifecycle.lock_all
19
+ end
20
+
21
+ # @param subscriptions_lifecycle [PgEventstore::SubscriptionsLifecycle]
22
+ # @return [void]
23
+ def start_runners(subscriptions_lifecycle)
24
+ subscriptions_lifecycle.runners.each(&:start)
25
+ end
26
+
27
+ # @param cmds_handler [PgEventstore::CommandsHandler]
28
+ # @return [void]
29
+ def start_cmds_handler(cmds_handler)
30
+ cmds_handler.start
31
+ end
32
+
33
+ # @param subscriptions_set_lifecycle [PgEventstore::SubscriptionsSetLifecycle]
34
+ # @param error [StandardError]
35
+ # @return [void]
36
+ def persist_error_info(subscriptions_set_lifecycle, error)
37
+ subscriptions_set_lifecycle.persisted_subscriptions_set.update(
38
+ last_error: Utils.error_info(error), last_error_occurred_at: Time.now.utc
39
+ )
40
+ end
41
+
42
+ # @param subscriptions_set_lifecycle [PgEventstore::SubscriptionsSetLifecycle]
43
+ # @param basic_runner [PgEventstore::BasicRunner]
44
+ # @param _error [StandardError]
45
+ # @return [void]
46
+ def restart_runner(subscriptions_set_lifecycle, basic_runner, _error)
47
+ subscriptions_set = subscriptions_set_lifecycle.persisted_subscriptions_set
48
+ return if subscriptions_set.restart_count >= subscriptions_set.max_restarts_number
49
+
50
+ Thread.new do
51
+ sleep subscriptions_set.time_between_restarts
52
+ basic_runner.restore
53
+ end
54
+ end
55
+
56
+ # @param subscriptions_set_lifecycle [PgEventstore::SubscriptionsSetLifecycle]
57
+ # @return [void]
58
+ def ping_subscriptions_set(subscriptions_set_lifecycle)
59
+ subscriptions_set_lifecycle.ping_subscriptions_set
60
+ end
61
+
62
+ # @param subscriptions_lifecycle [PgEventstore::SubscriptionsLifecycle]
63
+ # @param config_name [Symbol]
64
+ # @return [void]
65
+ def feed_runners(subscriptions_lifecycle, config_name)
66
+ SubscriptionRunnersFeeder.new(config_name).feed(subscriptions_lifecycle.runners)
67
+ end
68
+
69
+ # @param subscriptions_lifecycle [PgEventstore::SubscriptionsLifecycle]
70
+ # @return [void]
71
+ def ping_subscriptions(subscriptions_lifecycle)
72
+ subscriptions_lifecycle.ping_subscriptions
73
+ end
74
+
75
+ # @param subscriptions_lifecycle [PgEventstore::SubscriptionsLifecycle]
76
+ # @return [void]
77
+ def stop_runners(subscriptions_lifecycle)
78
+ subscriptions_lifecycle.runners.each(&:stop_async).each(&:wait_for_finish)
79
+ end
80
+
81
+ # @param subscriptions_set_lifecycle [PgEventstore::SubscriptionsSetLifecycle]
82
+ # @return [void]
83
+ def reset_subscriptions_set(subscriptions_set_lifecycle)
84
+ subscriptions_set_lifecycle.reset_subscriptions_set
85
+ end
86
+
87
+ # @param cmds_handler [PgEventstore::CommandsHandler]
88
+ # @return [void]
89
+ def stop_commands_handler(cmds_handler)
90
+ cmds_handler.stop
91
+ end
92
+
93
+ # @param subscriptions_set_lifecycle [PgEventstore::SubscriptionsSetLifecycle]
94
+ # @return [void]
95
+ def update_subscriptions_set_restarts(subscriptions_set_lifecycle)
96
+ subscriptions_set = subscriptions_set_lifecycle.persisted_subscriptions_set
97
+ subscriptions_set.update(
98
+ last_restarted_at: Time.now.utc, restart_count: subscriptions_set.restart_count + 1
99
+ )
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PgEventstore
4
+ class SubscriptionRunnerHandlers
5
+ include Extensions::CallbackHandlersExtension
6
+
7
+ class << self
8
+ # @param stats [PgEventstore::SubscriptionHandlerPerformance]
9
+ # @param action [Proc]
10
+ # @param _current_position [Integer]
11
+ # @return [void]
12
+ def track_exec_time(stats, action, _current_position)
13
+ stats.track_exec_time { action.call }
14
+ end
15
+
16
+ # @param subscription [PgEventstore::Subscription]
17
+ # @param stats [PgEventstore::SubscriptionHandlerPerformance]
18
+ # @param current_position [Integer]
19
+ # @return [void]
20
+ def update_subscription_stats(subscription, stats, current_position)
21
+ subscription.update(
22
+ average_event_processing_time: stats.average_event_processing_time,
23
+ current_position: current_position,
24
+ total_processed_events: subscription.total_processed_events + 1
25
+ )
26
+ end
27
+
28
+ # @param subscription [PgEventstore::Subscription]
29
+ # @param error [StandardError]
30
+ # @return [void]
31
+ def update_subscription_error(subscription, error)
32
+ subscription.update(last_error: Utils.error_info(error), last_error_occurred_at: Time.now.utc)
33
+ end
34
+
35
+ # @param subscription [PgEventstore::Subscription]
36
+ # @param restart_terminator [#call, nil]
37
+ # @param failed_subscription_notifier [#call, nil]
38
+ # @param events_processor [PgEventstore::EventsProcessor]
39
+ # @param error [StandardError]
40
+ # @return [void]
41
+ def restart_events_processor(subscription, restart_terminator, failed_subscription_notifier, events_processor,
42
+ error)
43
+ return if restart_terminator&.call(subscription.dup)
44
+ if subscription.restart_count >= subscription.max_restarts_number
45
+ return failed_subscription_notifier&.call(subscription.dup, error)
46
+ end
47
+
48
+ Thread.new do
49
+ sleep subscription.time_between_restarts
50
+ events_processor.restore
51
+ end
52
+ end
53
+
54
+ # @param subscription [PgEventstore::Subscription]
55
+ # @param global_position [Integer]
56
+ # @return [void]
57
+ def update_subscription_chunk_stats(subscription, global_position)
58
+ subscription.update(last_chunk_fed_at: Time.now.utc, last_chunk_greatest_position: global_position)
59
+ end
60
+
61
+ # @param subscription [PgEventstore::Subscription]
62
+ # @return [void]
63
+ def update_subscription_restarts(subscription)
64
+ subscription.update(last_restarted_at: Time.now.utc, restart_count: subscription.restart_count + 1)
65
+ end
66
+
67
+ # @param subscription [PgEventstore::Subscription]
68
+ # @param state [String]
69
+ # @return [void]
70
+ def update_subscription_state(subscription, state)
71
+ subscription.update(state: state)
72
+ end
73
+ end
74
+ end
75
+ end
@@ -31,35 +31,19 @@ module PgEventstore
31
31
  private
32
32
 
33
33
  def attach_runner_callbacks
34
- @basic_runner.define_callback(:process_async, :before, method(:process_async))
35
- @basic_runner.define_callback(:after_runner_died, :before, method(:after_runner_died))
36
- end
37
-
38
- def process_async
39
- subscription_feeder_commands.process
40
- subscription_runners_commands.process
41
- end
42
-
43
- # @param error [StandardError]
44
- # @return [void]
45
- def after_runner_died(error)
46
- PgEventstore.logger&.error "#{self.class.name}: Error occurred: #{error.message}"
47
- PgEventstore.logger&.error "#{self.class.name}: Backtrace: #{error.backtrace&.join("\n")}"
48
- PgEventstore.logger&.error "#{self.class.name}: Trying to auto-repair in #{RESTART_DELAY} seconds..."
49
- Thread.new do
50
- sleep RESTART_DELAY
51
- @basic_runner.restore
52
- end
53
- end
54
-
55
- # @return [PgEventstore::CommandHandlers::SubscriptionFeederCommands]
56
- def subscription_feeder_commands
57
- CommandHandlers::SubscriptionFeederCommands.new(@config_name, @subscription_feeder)
58
- end
59
-
60
- # @return [PgEventstore::CommandHandlers::SubscriptionRunnersCommands]
61
- def subscription_runners_commands
62
- CommandHandlers::SubscriptionRunnersCommands.new(@config_name, @runners, @subscription_feeder.id)
34
+ @basic_runner.define_callback(
35
+ :process_async, :before,
36
+ CommandsHandlerHandlers.setup_handler(:process_feeder_commands, @config_name, @subscription_feeder)
37
+ )
38
+ @basic_runner.define_callback(
39
+ :process_async, :before,
40
+ CommandsHandlerHandlers.setup_handler(:process_runners_commands, @config_name, @runners, @subscription_feeder)
41
+ )
42
+
43
+ @basic_runner.define_callback(
44
+ :after_runner_died, :before,
45
+ CommandsHandlerHandlers.setup_handler(:restore_runner, @basic_runner, RESTART_DELAY)
46
+ )
63
47
  end
64
48
  end
65
49
  end
@@ -26,7 +26,7 @@ module PgEventstore
26
26
  raise EmptyChunkFedError.new("Empty chunk was fed!") if raw_events.empty?
27
27
 
28
28
  within_state(:running) do
29
- callbacks.run_callbacks(:feed, global_position(raw_events.last))
29
+ callbacks.run_callbacks(:feed, Utils.original_global_position(raw_events.last))
30
30
  @raw_events.push(*raw_events)
31
31
  end
32
32
  end
@@ -44,47 +44,23 @@ module PgEventstore
44
44
 
45
45
  private
46
46
 
47
- # @param raw_event [Hash]
48
- # @return [void]
49
- def process_event(raw_event)
50
- callbacks.run_callbacks(:process, global_position(raw_event)) do
51
- @handler.call(raw_event)
52
- end
53
- end
54
-
55
47
  def attach_runner_callbacks
56
- @basic_runner.define_callback(:process_async, :before, method(:process_async))
57
- @basic_runner.define_callback(:after_runner_died, :before, method(:after_runner_died))
58
- @basic_runner.define_callback(:before_runner_restored, :before, method(:before_runner_restored))
59
- @basic_runner.define_callback(:change_state, :before, method(:change_state))
60
- end
61
-
62
- def process_async
63
- raw_event = @raw_events.shift
64
- return sleep 0.5 if raw_event.nil?
65
-
66
- process_event(raw_event)
67
- rescue
68
- @raw_events.unshift(raw_event)
69
- raise
70
- end
71
-
72
- def after_runner_died(...)
73
- callbacks.run_callbacks(:error, ...)
74
- end
75
-
76
- def before_runner_restored
77
- callbacks.run_callbacks(:restart)
78
- end
79
-
80
- def change_state(...)
81
- callbacks.run_callbacks(:change_state, ...)
82
- end
83
-
84
- # @param raw_event [Hash]
85
- # @return [Integer]
86
- def global_position(raw_event)
87
- raw_event['link'] ? raw_event['link']['global_position'] : raw_event['global_position']
48
+ @basic_runner.define_callback(
49
+ :process_async, :before,
50
+ EventsProcessorHandlers.setup_handler(:process_event, @callbacks, @handler, @raw_events)
51
+ )
52
+
53
+ @basic_runner.define_callback(
54
+ :after_runner_died, :before, EventsProcessorHandlers.setup_handler(:after_runner_died, callbacks)
55
+ )
56
+
57
+ @basic_runner.define_callback(
58
+ :before_runner_restored, :before, EventsProcessorHandlers.setup_handler(:before_runner_restored, callbacks)
59
+ )
60
+
61
+ @basic_runner.define_callback(
62
+ :change_state, :before, EventsProcessorHandlers.setup_handler(:change_state, callbacks)
63
+ )
88
64
  end
89
65
  end
90
66
  end