pg_eventstore 1.4.0 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
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