yes-core 2.5.0 → 2.6.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/CHANGELOG.md +6 -0
- data/lib/yes/core/authorization/cerbos_grpc_retry_policy.rb +17 -1
- data/lib/yes/core/read_model/builder.rb +33 -1
- data/lib/yes/core/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3628c3ea30a5599fa97c6533fd10d2214a0d5da009760b265fd0c11f8490349f
|
|
4
|
+
data.tar.gz: b223d9f7ba3ba16cc2f4d267aabfca2a2c5f6aa6335a3c4388a8f98edc5978dd
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d676304cb10bdc7714ce0b3f4cd45bbcbf85242bd9ce75f13a1ef3683ed042e6849378f007ccaedc448af1cbf4a49b4b2e770c5606474c7e7dd052d59cd9077b
|
|
7
|
+
data.tar.gz: a27b098783deeee35962fa5694f4fdaff7fd26a58d58b0a66bf6f799ca0d8ad1d0c79da259e266aec823abe450cdcde3942821e8fa8f3d6caece61115779eadd
|
data/CHANGELOG.md
CHANGED
|
@@ -11,7 +11,14 @@ module Yes
|
|
|
11
11
|
# caller never sees a `Cerbos::Error::Unavailable` for a blip that a second attempt on a
|
|
12
12
|
# healthy pod would have answered.
|
|
13
13
|
#
|
|
14
|
+
# A refused connection (a pod that stopped listening but is still routed to) also puts the
|
|
15
|
+
# channel into reconnect backoff, during which every call fails immediately. gRPC's default
|
|
16
|
+
# backoff (1s, growing to 120s) outlasts the retry window above, so a single process would
|
|
17
|
+
# keep failing every request for many seconds. The reconnect backoff is therefore capped to
|
|
18
|
+
# the same order of magnitude as the retry backoff.
|
|
19
|
+
#
|
|
14
20
|
# @see https://grpc.io/docs/guides/retry/
|
|
21
|
+
# @see https://github.com/grpc/grpc/blob/master/doc/connection-backoff.md
|
|
15
22
|
module CerbosGrpcRetryPolicy
|
|
16
23
|
SERVICE_NAME = 'cerbos.svc.v1.CerbosService'
|
|
17
24
|
MAX_ATTEMPTS = 4
|
|
@@ -23,12 +30,21 @@ module Yes
|
|
|
23
30
|
ENABLE_RETRIES_ARG = 'grpc.enable_retries'
|
|
24
31
|
SERVICE_CONFIG_ARG = 'grpc.service_config'
|
|
25
32
|
|
|
33
|
+
RECONNECT_BACKOFF_MS = 100
|
|
34
|
+
MAX_RECONNECT_BACKOFF_MS = 1_000
|
|
35
|
+
MIN_RECONNECT_BACKOFF_ARG = 'grpc.min_reconnect_backoff_ms'
|
|
36
|
+
INITIAL_RECONNECT_BACKOFF_ARG = 'grpc.initial_reconnect_backoff_ms'
|
|
37
|
+
MAX_RECONNECT_BACKOFF_ARG = 'grpc.max_reconnect_backoff_ms'
|
|
38
|
+
|
|
26
39
|
class << self
|
|
27
40
|
# @return [Hash{String => Integer, String}] channel arguments for `Cerbos::Client.new`
|
|
28
41
|
def channel_args
|
|
29
42
|
{
|
|
30
43
|
ENABLE_RETRIES_ARG => 1,
|
|
31
|
-
SERVICE_CONFIG_ARG => service_config.to_json
|
|
44
|
+
SERVICE_CONFIG_ARG => service_config.to_json,
|
|
45
|
+
MIN_RECONNECT_BACKOFF_ARG => RECONNECT_BACKOFF_MS,
|
|
46
|
+
INITIAL_RECONNECT_BACKOFF_ARG => RECONNECT_BACKOFF_MS,
|
|
47
|
+
MAX_RECONNECT_BACKOFF_ARG => MAX_RECONNECT_BACKOFF_MS
|
|
32
48
|
}
|
|
33
49
|
end
|
|
34
50
|
|
|
@@ -23,7 +23,13 @@ module Yes
|
|
|
23
23
|
READ_MODEL_CLASS_REGEXP =
|
|
24
24
|
/(?<context>\w+)::ReadModels::(?<version>V\d+)?(::)?(?<aggregate>\w+)/
|
|
25
25
|
|
|
26
|
-
#
|
|
26
|
+
# Column of the read model that holds the revision of the last processed event of its stream
|
|
27
|
+
REVISION_COLUMN = :revision
|
|
28
|
+
|
|
29
|
+
# Based on event type class it distributes event to a proper event handler. After the handler ran, the
|
|
30
|
+
# stream revision of the event is stored in the read model's `revision` column (see #write_stream_revision).
|
|
31
|
+
# Events that were not handled (no handler, locale not available) do not change the revision, because
|
|
32
|
+
# the read model does not reflect them.
|
|
27
33
|
# @param event [Yes::Core::Event]
|
|
28
34
|
# @param read_model [ActiveRecord::Base] AR object
|
|
29
35
|
# @return [void]
|
|
@@ -47,6 +53,8 @@ module Yes
|
|
|
47
53
|
ensure
|
|
48
54
|
otl_record_processed(read_model, event, handler)
|
|
49
55
|
end
|
|
56
|
+
|
|
57
|
+
write_stream_revision(read_model, event)
|
|
50
58
|
end
|
|
51
59
|
otl_trackable :call, OpenTelemetry::OtlSpan::OtlData.new(
|
|
52
60
|
span_kind: :consumer,
|
|
@@ -172,6 +180,30 @@ module Yes
|
|
|
172
180
|
READ_MODEL_CLASS_REGEXP.match(self.class.to_s)
|
|
173
181
|
end
|
|
174
182
|
|
|
183
|
+
# Stores the stream revision of the event in the read model's `revision` column, so a consumer can tell
|
|
184
|
+
# how far a read model fed by a subscription has caught up with its stream. It only moves forward and
|
|
185
|
+
# skips read models without the column. Per-aggregate columns (e.g. `shop_order_revision`) belong to
|
|
186
|
+
# the aggregates that write them and are never touched here.
|
|
187
|
+
# It only writes for events of the read model's own stream: a builder may also react to events of
|
|
188
|
+
# other streams (e.g. a product event for an order item), whose revision says nothing about this row.
|
|
189
|
+
# Only the stream id is compared, not the context or the stream name. A read model fed by two streams
|
|
190
|
+
# that share the same id would get a mixed revision, so such read models must not rely on it.
|
|
191
|
+
# A read model whose `revision` column an aggregate writes must not also be fed by a builder:
|
|
192
|
+
# use per-aggregate revision columns or project the events through the aggregate instead.
|
|
193
|
+
# @param read_model [ActiveRecord::Base, nil] the read model, nil if the event maps to no row
|
|
194
|
+
# @param event [Yes::Core::Event] the event that was handled
|
|
195
|
+
# @return [void]
|
|
196
|
+
def write_stream_revision(read_model, event)
|
|
197
|
+
revision = event.stream_revision
|
|
198
|
+
return unless revision && read_model&.persisted? && read_model.has_attribute?(REVISION_COLUMN)
|
|
199
|
+
return unless event.stream&.stream_id == read_model.id
|
|
200
|
+
|
|
201
|
+
# a nullable column may still be NULL before the first event
|
|
202
|
+
return unless revision > (read_model[REVISION_COLUMN] || -1)
|
|
203
|
+
|
|
204
|
+
read_model.update_column(REVISION_COLUMN, revision)
|
|
205
|
+
end
|
|
206
|
+
|
|
175
207
|
# @param locale [Symbol] locale to check
|
|
176
208
|
# @return [Boolean] true if locale is available
|
|
177
209
|
def correct_locale?(locale)
|
data/lib/yes/core/version.rb
CHANGED