pg_eventstore 1.0.3 → 1.0.4
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/CHANGELOG.md +4 -0
- data/lib/pg_eventstore/errors.rb +3 -0
- data/lib/pg_eventstore/queries/subscription_queries.rb +16 -0
- data/lib/pg_eventstore/subscriptions/events_processor.rb +4 -4
- data/lib/pg_eventstore/subscriptions/subscription.rb +22 -1
- data/lib/pg_eventstore/subscriptions/subscription_feeder.rb +19 -3
- data/lib/pg_eventstore/subscriptions/subscription_runner.rb +6 -5
- data/lib/pg_eventstore/subscriptions/subscription_runners_feeder.rb +2 -1
- data/lib/pg_eventstore/version.rb +1 -1
- data/lib/pg_eventstore/web/subscriptions/helpers.rb +2 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d5a69951bc18bd74869eb843b9e017a1c1f238bfc17750400e30b99f7d7b9f2d
|
4
|
+
data.tar.gz: 56ce94941096227944e8d5f11b9c7f9ca2f1fd816ad477cb02abe58604945c47
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f2f682990d1450b874e3d1ad9cf68e3e1cf7dcd546c78bb101982c5a03c5f355f31101442b2dd9a2c59531535e02eff01b12b119c79beca331f7262e927ebe5c
|
7
|
+
data.tar.gz: 2b2624a388eba5772c6a3bdd601ffe6fbcdb3c08c0d3c4585c1dfcf03862cf94f19e39db453950294f1a5a01a35e5ee33c975632c7ba6a2c966fcb85ff6dbb5d
|
data/CHANGELOG.md
CHANGED
data/lib/pg_eventstore/errors.rb
CHANGED
@@ -101,6 +101,22 @@ module PgEventstore
|
|
101
101
|
deserialize(updated_attrs)
|
102
102
|
end
|
103
103
|
|
104
|
+
# @param subscriptions_set_id [Integer] SubscriptionsSet#id
|
105
|
+
# @param subscriptions_ids [Array<Integer>] Array of Subscription#id
|
106
|
+
# @return [Hash<Integer => Time>]
|
107
|
+
def ping_all(subscriptions_set_id, subscriptions_ids)
|
108
|
+
pg_result = connection.with do |conn|
|
109
|
+
sql = <<~SQL
|
110
|
+
UPDATE subscriptions SET updated_at = $1 WHERE locked_by = $2 AND id = ANY($3::int[])
|
111
|
+
RETURNING id, updated_at
|
112
|
+
SQL
|
113
|
+
conn.exec_params(sql, [Time.now.utc, subscriptions_set_id, subscriptions_ids])
|
114
|
+
end
|
115
|
+
pg_result.to_h do |attrs|
|
116
|
+
[attrs['id'], attrs['updated_at']]
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
104
120
|
# @param query_options [Hash{Integer => Hash}] runner_id/query options association
|
105
121
|
# @return [Hash{Integer => Hash}] runner_id/events association
|
106
122
|
def subscriptions_events(query_options)
|
@@ -20,6 +20,8 @@ module PgEventstore
|
|
20
20
|
# @param raw_events [Array<Hash>]
|
21
21
|
# @return [void]
|
22
22
|
def feed(raw_events)
|
23
|
+
raise EmptyChunkFedError.new("Empty chunk was fed!") if raw_events.empty?
|
24
|
+
|
23
25
|
callbacks.run_callbacks(:feed, global_position(raw_events.last))
|
24
26
|
@raw_events.push(*raw_events)
|
25
27
|
end
|
@@ -69,11 +71,9 @@ module PgEventstore
|
|
69
71
|
callbacks.run_callbacks(:change_state, ...)
|
70
72
|
end
|
71
73
|
|
72
|
-
# @param raw_event [Hash
|
73
|
-
# @return [Integer
|
74
|
+
# @param raw_event [Hash]
|
75
|
+
# @return [Integer]
|
74
76
|
def global_position(raw_event)
|
75
|
-
return unless raw_event
|
76
|
-
|
77
77
|
raw_event['link'] ? raw_event['link']['global_position'] : raw_event['global_position']
|
78
78
|
end
|
79
79
|
end
|
@@ -73,6 +73,25 @@ module PgEventstore
|
|
73
73
|
# @return [Time]
|
74
74
|
attribute(:updated_at)
|
75
75
|
|
76
|
+
class << self
|
77
|
+
# @param subscriptions_set_id [Integer] SubscriptionsSet#id
|
78
|
+
# @param subscriptions [Array<PgEventstoreSubscription>]
|
79
|
+
# @return [void]
|
80
|
+
def ping_all(subscriptions_set_id, subscriptions)
|
81
|
+
result = subscription_queries.ping_all(subscriptions_set_id, subscriptions.map(&:id))
|
82
|
+
subscriptions.each do |subscription|
|
83
|
+
next unless result[subscription.id]
|
84
|
+
|
85
|
+
subscription.assign_attributes(updated_at: result[subscription.id])
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# @return [PgEventstore::SubscriptionQueries]
|
90
|
+
def subscription_queries
|
91
|
+
SubscriptionQueries.new(connection)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
76
95
|
def options=(val)
|
77
96
|
@options = Utils.deep_transform_keys(val, &:to_sym)
|
78
97
|
end
|
@@ -135,6 +154,7 @@ module PgEventstore
|
|
135
154
|
|
136
155
|
private
|
137
156
|
|
157
|
+
# @return [void]
|
138
158
|
def reset_runtime_attributes
|
139
159
|
update(
|
140
160
|
options: options,
|
@@ -151,8 +171,9 @@ module PgEventstore
|
|
151
171
|
)
|
152
172
|
end
|
153
173
|
|
174
|
+
# @return [PgEventstore::SubscriptionQueries]
|
154
175
|
def subscription_queries
|
155
|
-
|
176
|
+
self.class.subscription_queries
|
156
177
|
end
|
157
178
|
end
|
158
179
|
end
|
@@ -24,7 +24,7 @@ module PgEventstore
|
|
24
24
|
@commands_handler = CommandsHandler.new(@config_name, self, @runners)
|
25
25
|
@basic_runner = BasicRunner.new(0.2, 0)
|
26
26
|
@force_lock = false
|
27
|
-
@
|
27
|
+
@subscriptions_pinged_at = Time.at(0)
|
28
28
|
attach_runner_callbacks
|
29
29
|
end
|
30
30
|
|
@@ -100,6 +100,7 @@ module PgEventstore
|
|
100
100
|
@basic_runner.define_callback(:after_runner_died, :after, method(:restart_runner))
|
101
101
|
@basic_runner.define_callback(:process_async, :before, method(:ping_subscriptions_set))
|
102
102
|
@basic_runner.define_callback(:process_async, :before, method(:process_async))
|
103
|
+
@basic_runner.define_callback(:process_async, :after, method(:ping_subscriptions))
|
103
104
|
@basic_runner.define_callback(:after_runner_stopped, :before, method(:after_runner_stopped))
|
104
105
|
@basic_runner.define_callback(:before_runner_restored, :after, method(:update_runner_restarts))
|
105
106
|
end
|
@@ -140,10 +141,25 @@ module PgEventstore
|
|
140
141
|
|
141
142
|
# @return [void]
|
142
143
|
def ping_subscriptions_set
|
143
|
-
return
|
144
|
+
return if subscriptions_set.updated_at > Time.now.utc - HEARTBEAT_INTERVAL
|
144
145
|
|
145
146
|
subscriptions_set.update(updated_at: Time.now.utc)
|
146
|
-
|
147
|
+
end
|
148
|
+
|
149
|
+
# @return [void]
|
150
|
+
def ping_subscriptions
|
151
|
+
return if @subscriptions_pinged_at > Time.now.utc - HEARTBEAT_INTERVAL
|
152
|
+
|
153
|
+
runners = @runners.select do |runner|
|
154
|
+
next false unless runner.running?
|
155
|
+
|
156
|
+
runner.subscription.updated_at < Time.now.utc - HEARTBEAT_INTERVAL
|
157
|
+
end
|
158
|
+
unless runners.empty?
|
159
|
+
Subscription.using_connection(@config_name).ping_all(subscriptions_set.id, runners.map(&:subscription))
|
160
|
+
end
|
161
|
+
|
162
|
+
@subscriptions_pinged_at = Time.now.utc
|
147
163
|
end
|
148
164
|
|
149
165
|
# @return [void]
|
@@ -11,6 +11,7 @@ module PgEventstore
|
|
11
11
|
extend Forwardable
|
12
12
|
|
13
13
|
MAX_EVENTS_PER_CHUNK = 1_000
|
14
|
+
MIN_EVENTS_PER_CHUNK = 10
|
14
15
|
INITIAL_EVENTS_PER_CHUNK = 10
|
15
16
|
|
16
17
|
attr_reader :subscription
|
@@ -56,7 +57,10 @@ module PgEventstore
|
|
56
57
|
return INITIAL_EVENTS_PER_CHUNK if @stats.average_event_processing_time.zero?
|
57
58
|
|
58
59
|
events_per_chunk = (@subscription.chunk_query_interval / @stats.average_event_processing_time).round
|
59
|
-
[
|
60
|
+
events_to_fetch = [events_per_chunk, MAX_EVENTS_PER_CHUNK].min - @events_processor.events_left_in_chunk
|
61
|
+
return 0 if events_to_fetch < 0 # We still have a lot of events in the chunk - no need to fetch more
|
62
|
+
|
63
|
+
[events_to_fetch, MIN_EVENTS_PER_CHUNK].max
|
60
64
|
end
|
61
65
|
|
62
66
|
# @return [void]
|
@@ -103,12 +107,9 @@ module PgEventstore
|
|
103
107
|
@subscription.update(last_error: Utils.error_info(error), last_error_occurred_at: Time.now.utc)
|
104
108
|
end
|
105
109
|
|
106
|
-
# @param global_position [Integer
|
110
|
+
# @param global_position [Integer]
|
107
111
|
# @return [void]
|
108
112
|
def update_subscription_chunk_stats(global_position)
|
109
|
-
# nil means subscriptions events query were executed, but there were no new events
|
110
|
-
return @subscription.update(updated_at: Time.now.utc) if global_position.nil?
|
111
|
-
|
112
113
|
@subscription.update(last_chunk_fed_at: Time.now.utc, last_chunk_greatest_position: global_position)
|
113
114
|
end
|
114
115
|
|
@@ -17,8 +17,9 @@ module PgEventstore
|
|
17
17
|
|
18
18
|
runners_query_options = runners.to_h { |runner| [runner.id, runner.next_chunk_query_opts] }
|
19
19
|
grouped_events = subscription_queries.subscriptions_events(runners_query_options)
|
20
|
+
|
20
21
|
runners.each do |runner|
|
21
|
-
runner.feed(grouped_events[runner.id]
|
22
|
+
runner.feed(grouped_events[runner.id]) if grouped_events[runner.id]
|
22
23
|
end
|
23
24
|
end
|
24
25
|
|
@@ -43,7 +43,8 @@ module PgEventstore
|
|
43
43
|
# @return [String] html status
|
44
44
|
def colored_state(state, updated_at)
|
45
45
|
if state == RunnerState::STATES[:running]
|
46
|
-
|
46
|
+
# -1 is added as a margin to prevent false-positive result
|
47
|
+
if updated_at < Time.now.utc - SubscriptionFeeder::HEARTBEAT_INTERVAL - 1
|
47
48
|
title = <<~TEXT
|
48
49
|
Something is wrong. Last update was more than #{SubscriptionFeeder::HEARTBEAT_INTERVAL} seconds \
|
49
50
|
ago(#{updated_at}).
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pg_eventstore
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ivan Dzyzenko
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-06-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: pg
|