smplkit 3.0.95 → 3.0.96
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/lib/smplkit/account/client.rb +121 -0
- data/lib/smplkit/account/models.rb +53 -0
- data/lib/smplkit/api_support.rb +83 -0
- data/lib/smplkit/audit/client.rb +9 -10
- data/lib/smplkit/{management/audit.rb → audit/forwarders.rb} +73 -76
- data/lib/smplkit/audit/models.rb +40 -1
- data/lib/smplkit/buffers.rb +235 -0
- data/lib/smplkit/client.rb +126 -67
- data/lib/smplkit/config/client.rb +617 -182
- data/lib/smplkit/config_resolution.rb +11 -5
- data/lib/smplkit/errors.rb +8 -0
- data/lib/smplkit/flags/client.rb +472 -114
- data/lib/smplkit/flags/types.rb +6 -7
- data/lib/smplkit/{management/jobs.rb → jobs/client.rb} +148 -89
- data/lib/smplkit/logging/client.rb +647 -192
- data/lib/smplkit/logging/helpers.rb +1 -0
- data/lib/smplkit/logging/models.rb +92 -1
- data/lib/smplkit/logging/sources.rb +1 -1
- data/lib/smplkit/platform/client.rb +472 -0
- data/lib/smplkit/platform/models.rb +182 -0
- data/lib/smplkit/{management → platform}/types.rb +7 -4
- data/lib/smplkit/transport.rb +99 -0
- data/lib/smplkit.rb +18 -6
- metadata +11 -7
- data/lib/smplkit/management/buffer.rb +0 -198
- data/lib/smplkit/management/client.rb +0 -1074
- data/lib/smplkit/management/models.rb +0 -178
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Smplkit
|
|
4
|
+
module Platform
|
|
5
|
+
# Accept Color, hex string, or nil; reject anything else.
|
|
6
|
+
def self.coerce_color(value)
|
|
7
|
+
return value if value.nil? || value.is_a?(Color)
|
|
8
|
+
return Color.new(value) if value.is_a?(String)
|
|
9
|
+
|
|
10
|
+
raise TypeError, "color must be a Color, hex string, or nil; got #{value.class}: #{value.inspect}"
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Environment resource (sync). Mutate fields, then call +save+.
|
|
14
|
+
class Environment
|
|
15
|
+
attr_accessor :id, :name, :classification, :created_at, :updated_at
|
|
16
|
+
attr_reader :color
|
|
17
|
+
|
|
18
|
+
def initialize(client = nil, name:, id: nil, color: nil,
|
|
19
|
+
classification: EnvironmentClassification::STANDARD,
|
|
20
|
+
created_at: nil, updated_at: nil)
|
|
21
|
+
@client = client
|
|
22
|
+
@id = id
|
|
23
|
+
@name = name
|
|
24
|
+
@color = Platform.coerce_color(color)
|
|
25
|
+
@classification = classification
|
|
26
|
+
@created_at = created_at
|
|
27
|
+
@updated_at = updated_at
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def color=(value)
|
|
31
|
+
@color = Platform.coerce_color(value)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Create or update this environment on the server.
|
|
35
|
+
def save
|
|
36
|
+
raise "Environment was constructed without a client; cannot save" if @client.nil?
|
|
37
|
+
|
|
38
|
+
other = @created_at.nil? ? @client._create(self) : @client._update(self)
|
|
39
|
+
_apply(other)
|
|
40
|
+
self
|
|
41
|
+
end
|
|
42
|
+
alias save! save
|
|
43
|
+
|
|
44
|
+
# Delete this environment from the server.
|
|
45
|
+
def delete
|
|
46
|
+
raise "Environment was constructed without a client or id; cannot delete" if @client.nil? || @id.nil?
|
|
47
|
+
|
|
48
|
+
@client.delete(@id)
|
|
49
|
+
end
|
|
50
|
+
alias delete! delete
|
|
51
|
+
|
|
52
|
+
def to_s
|
|
53
|
+
"Environment(id=#{@id.inspect}, name=#{@name.inspect}, classification=#{@classification.inspect})"
|
|
54
|
+
end
|
|
55
|
+
alias inspect to_s
|
|
56
|
+
|
|
57
|
+
def _apply(other)
|
|
58
|
+
@id = other.id
|
|
59
|
+
@name = other.name
|
|
60
|
+
@color = other.color
|
|
61
|
+
@classification = other.classification
|
|
62
|
+
@created_at = other.created_at
|
|
63
|
+
@updated_at = other.updated_at
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Service resource (sync). Mutate fields, then call +save+.
|
|
68
|
+
class Service
|
|
69
|
+
attr_accessor :id, :name, :created_at, :updated_at
|
|
70
|
+
|
|
71
|
+
def initialize(client = nil, name:, id: nil, created_at: nil, updated_at: nil)
|
|
72
|
+
@client = client
|
|
73
|
+
@id = id
|
|
74
|
+
@name = name
|
|
75
|
+
@created_at = created_at
|
|
76
|
+
@updated_at = updated_at
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Create or update this service on the server.
|
|
80
|
+
def save
|
|
81
|
+
raise "Service was constructed without a client; cannot save" if @client.nil?
|
|
82
|
+
|
|
83
|
+
other = @created_at.nil? ? @client._create(self) : @client._update(self)
|
|
84
|
+
_apply(other)
|
|
85
|
+
self
|
|
86
|
+
end
|
|
87
|
+
alias save! save
|
|
88
|
+
|
|
89
|
+
# Delete this service from the server.
|
|
90
|
+
def delete
|
|
91
|
+
raise "Service was constructed without a client or id; cannot delete" if @client.nil? || @id.nil?
|
|
92
|
+
|
|
93
|
+
@client.delete(@id)
|
|
94
|
+
end
|
|
95
|
+
alias delete! delete
|
|
96
|
+
|
|
97
|
+
def to_s
|
|
98
|
+
"Service(id=#{@id.inspect}, name=#{@name.inspect})"
|
|
99
|
+
end
|
|
100
|
+
alias inspect to_s
|
|
101
|
+
|
|
102
|
+
def _apply(other)
|
|
103
|
+
@id = other.id
|
|
104
|
+
@name = other.name
|
|
105
|
+
@created_at = other.created_at
|
|
106
|
+
@updated_at = other.updated_at
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# A context type resource (e.g. "user", "account").
|
|
111
|
+
class ContextType
|
|
112
|
+
attr_accessor :id, :name, :attributes, :created_at, :updated_at
|
|
113
|
+
|
|
114
|
+
def initialize(client = nil, name:, id: nil, attributes: nil, created_at: nil, updated_at: nil)
|
|
115
|
+
@client = client
|
|
116
|
+
@id = id
|
|
117
|
+
@name = name
|
|
118
|
+
@attributes = attributes ? deep_dup_attrs(attributes) : {}
|
|
119
|
+
@created_at = created_at
|
|
120
|
+
@updated_at = updated_at
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# Add a known-attribute slot. Local; call +save+ to persist.
|
|
124
|
+
def add_attribute(name, **metadata)
|
|
125
|
+
@attributes[name] = stringify_meta(metadata)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# Remove a known-attribute slot. Local; call +save+ to persist.
|
|
129
|
+
def remove_attribute(name)
|
|
130
|
+
@attributes.delete(name)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# Replace a known-attribute slot's metadata. Local; call +save+.
|
|
134
|
+
def update_attribute(name, **metadata)
|
|
135
|
+
@attributes[name] = stringify_meta(metadata)
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
# Create or update this context type on the server.
|
|
139
|
+
def save
|
|
140
|
+
raise "ContextType was constructed without a client; cannot save" if @client.nil?
|
|
141
|
+
|
|
142
|
+
other = @created_at.nil? ? @client._create(self) : @client._update(self)
|
|
143
|
+
_apply(other)
|
|
144
|
+
self
|
|
145
|
+
end
|
|
146
|
+
alias save! save
|
|
147
|
+
|
|
148
|
+
# Delete this context type from the server.
|
|
149
|
+
def delete
|
|
150
|
+
raise "ContextType was constructed without a client or id; cannot delete" if @client.nil? || @id.nil?
|
|
151
|
+
|
|
152
|
+
@client.delete(@id)
|
|
153
|
+
end
|
|
154
|
+
alias delete! delete
|
|
155
|
+
|
|
156
|
+
def to_s
|
|
157
|
+
"ContextType(id=#{@id.inspect}, name=#{@name.inspect})"
|
|
158
|
+
end
|
|
159
|
+
alias inspect to_s
|
|
160
|
+
|
|
161
|
+
def _apply(other)
|
|
162
|
+
@id = other.id
|
|
163
|
+
@name = other.name
|
|
164
|
+
@attributes = deep_dup_attrs(other.attributes)
|
|
165
|
+
@created_at = other.created_at
|
|
166
|
+
@updated_at = other.updated_at
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
private
|
|
170
|
+
|
|
171
|
+
def stringify_meta(metadata)
|
|
172
|
+
metadata.each_with_object({}) { |(k, v), out| out[k.to_s] = v }
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def deep_dup_attrs(attrs)
|
|
176
|
+
attrs.each_with_object({}) do |(k, v), out|
|
|
177
|
+
out[k.to_s] = v.is_a?(Hash) ? stringify_meta(v) : v
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
end
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Smplkit
|
|
4
|
-
module
|
|
4
|
+
module Platform
|
|
5
5
|
# Whether an environment participates in the canonical ordering.
|
|
6
6
|
#
|
|
7
7
|
# +STANDARD+ environments are the customer's deploy targets — production,
|
|
8
|
-
# staging, development, etc.
|
|
8
|
+
# staging, development, etc. They participate in
|
|
9
|
+
# +account.settings.environment_order+ and appear in the standard Console
|
|
10
|
+
# environment columns.
|
|
11
|
+
#
|
|
9
12
|
# +AD_HOC+ environments are transient targets (preview branches, individual
|
|
10
13
|
# developer sandboxes) that should not appear in the standard ordering.
|
|
11
14
|
module EnvironmentClassification
|
|
@@ -60,6 +63,6 @@ module Smplkit
|
|
|
60
63
|
end
|
|
61
64
|
end
|
|
62
65
|
|
|
63
|
-
Color =
|
|
64
|
-
EnvironmentClassification =
|
|
66
|
+
Color = Platform::Color
|
|
67
|
+
EnvironmentClassification = Platform::EnvironmentClassification
|
|
65
68
|
end
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "uri"
|
|
4
|
+
|
|
5
|
+
module Smplkit
|
|
6
|
+
# Internal per-service HTTP transport construction.
|
|
7
|
+
#
|
|
8
|
+
# The top-level +Smplkit::Client+ needs one authenticated transport per
|
|
9
|
+
# backend service (app, config, flags, logging, jobs) plus a
|
|
10
|
+
# context-registration buffer that +client.platform+ owns. This module builds
|
|
11
|
+
# them in one place so the construction is side-effect-free (transports
|
|
12
|
+
# connect lazily on first call) and shared by the top-level client.
|
|
13
|
+
#
|
|
14
|
+
# There is no audit transport here — +client.audit+ owns its own.
|
|
15
|
+
module Transport
|
|
16
|
+
SDK_OWNED_HEADERS = %w[authorization content-type user-agent].freeze
|
|
17
|
+
|
|
18
|
+
module_function
|
|
19
|
+
|
|
20
|
+
# Project the runtime +ResolvedConfig+ down to the transport subset.
|
|
21
|
+
#
|
|
22
|
+
# The top-level client's resolved config is a superset of what the
|
|
23
|
+
# transports need; this drops the runtime-only fields (environment,
|
|
24
|
+
# service, telemetry).
|
|
25
|
+
def to_transport_config(cfg, extra_headers = nil)
|
|
26
|
+
ConfigResolution::ResolvedManagementConfig.new(
|
|
27
|
+
api_key: cfg.api_key,
|
|
28
|
+
base_domain: cfg.base_domain,
|
|
29
|
+
scheme: cfg.scheme,
|
|
30
|
+
debug: cfg.debug,
|
|
31
|
+
extra_headers: extra_headers
|
|
32
|
+
)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# The per-service authenticated transports built for a top-level client.
|
|
36
|
+
#
|
|
37
|
+
# Construction is side-effect-free: each transport connects lazily on its
|
|
38
|
+
# first call. +app_url+ is carried alongside so the account settings client
|
|
39
|
+
# and the WebSocket can reach the app service. +close+ tears down the
|
|
40
|
+
# underlying Faraday connection pools.
|
|
41
|
+
ServiceTransports = Struct.new(
|
|
42
|
+
:app_url, :api_key, :app_http, :config_http, :flags_http, :logging_http, :jobs_http,
|
|
43
|
+
keyword_init: true
|
|
44
|
+
) do
|
|
45
|
+
def close
|
|
46
|
+
# The generated ApiClient owns Faraday connections that release on GC.
|
|
47
|
+
# No explicit shutdown is exposed; this stub keeps the API stable.
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Build the five per-service transports from a resolved transport config.
|
|
52
|
+
#
|
|
53
|
+
# Side-effect-free — the underlying Faraday clients are created lazily on
|
|
54
|
+
# the first request. Smpl Jobs is JSON:API, so its transport carries the
|
|
55
|
+
# +application/vnd.api+json+ Accept header.
|
|
56
|
+
def build_service_transports(cfg)
|
|
57
|
+
app_url = ConfigResolution.service_url(cfg.scheme, "app", cfg.base_domain)
|
|
58
|
+
ServiceTransports.new(
|
|
59
|
+
app_url: app_url,
|
|
60
|
+
api_key: cfg.api_key,
|
|
61
|
+
app_http: build_api_client(SmplkitGeneratedClient::App, "app", cfg),
|
|
62
|
+
config_http: build_api_client(SmplkitGeneratedClient::Config, "config", cfg),
|
|
63
|
+
flags_http: build_api_client(SmplkitGeneratedClient::Flags, "flags", cfg),
|
|
64
|
+
logging_http: build_api_client(SmplkitGeneratedClient::Logging, "logging", cfg),
|
|
65
|
+
jobs_http: build_api_client(SmplkitGeneratedClient::Jobs, "jobs", cfg,
|
|
66
|
+
accept: "application/vnd.api+json")
|
|
67
|
+
)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Build a generated +ApiClient+ for one service from a resolved config.
|
|
71
|
+
#
|
|
72
|
+
# +base_url+, when supplied, overrides the +scheme+/+host+ derived from
|
|
73
|
+
# +subdomain+/+base_domain+ (the path a standalone product client takes
|
|
74
|
+
# when handed a fully-resolved app URL).
|
|
75
|
+
def build_api_client(generated_module, subdomain, cfg, accept: nil, base_url: nil)
|
|
76
|
+
configuration = generated_module::Configuration.new
|
|
77
|
+
if base_url.nil?
|
|
78
|
+
configuration.scheme = cfg.scheme
|
|
79
|
+
configuration.host = "#{subdomain}.#{cfg.base_domain}"
|
|
80
|
+
else
|
|
81
|
+
uri = URI.parse(base_url)
|
|
82
|
+
configuration.scheme = uri.scheme
|
|
83
|
+
port_suffix = uri.port && ![80, 443].include?(uri.port) ? ":#{uri.port}" : ""
|
|
84
|
+
configuration.host = "#{uri.host}#{port_suffix}"
|
|
85
|
+
end
|
|
86
|
+
configuration.base_path = ""
|
|
87
|
+
configuration.access_token = cfg.api_key
|
|
88
|
+
configuration.debugging = cfg.debug
|
|
89
|
+
HttpPool.configure(configuration)
|
|
90
|
+
generated_module::ApiClient.new(configuration).tap do |client|
|
|
91
|
+
client.default_headers["User-Agent"] = "smplkit-ruby-sdk/#{Smplkit::VERSION}"
|
|
92
|
+
client.default_headers["Accept"] = accept if accept
|
|
93
|
+
(cfg.extra_headers || {}).each do |k, v|
|
|
94
|
+
client.default_headers[k] = v unless SDK_OWNED_HEADERS.include?(k.downcase)
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
data/lib/smplkit.rb
CHANGED
|
@@ -44,9 +44,25 @@ require_relative "smplkit/context"
|
|
|
44
44
|
require_relative "smplkit/config_resolution"
|
|
45
45
|
require_relative "smplkit/metrics"
|
|
46
46
|
require_relative "smplkit/ws"
|
|
47
|
+
|
|
48
|
+
# Internal foundation shared by every product client.
|
|
49
|
+
require_relative "smplkit/buffers"
|
|
50
|
+
require_relative "smplkit/api_support"
|
|
51
|
+
require_relative "smplkit/transport"
|
|
52
|
+
|
|
53
|
+
# Flags types (incl. Context) load before platform, which references Context.
|
|
47
54
|
require_relative "smplkit/flags/types"
|
|
48
55
|
require_relative "smplkit/flags/models"
|
|
49
56
|
require_relative "smplkit/flags/helpers"
|
|
57
|
+
|
|
58
|
+
# Platform + account (the cross-cutting surfaces) before the product clients
|
|
59
|
+
# that borrow them.
|
|
60
|
+
require_relative "smplkit/platform/types"
|
|
61
|
+
require_relative "smplkit/platform/models"
|
|
62
|
+
require_relative "smplkit/platform/client"
|
|
63
|
+
require_relative "smplkit/account/models"
|
|
64
|
+
require_relative "smplkit/account/client"
|
|
65
|
+
|
|
50
66
|
require_relative "smplkit/flags/client"
|
|
51
67
|
require_relative "smplkit/config/models"
|
|
52
68
|
require_relative "smplkit/config/helpers"
|
|
@@ -66,14 +82,10 @@ require_relative "smplkit/audit/events"
|
|
|
66
82
|
require_relative "smplkit/audit/resource_types"
|
|
67
83
|
require_relative "smplkit/audit/event_types"
|
|
68
84
|
require_relative "smplkit/audit/categories"
|
|
85
|
+
require_relative "smplkit/audit/forwarders"
|
|
69
86
|
require_relative "smplkit/audit/client"
|
|
70
87
|
require_relative "smplkit/jobs/models"
|
|
71
|
-
require_relative "smplkit/
|
|
72
|
-
require_relative "smplkit/management/models"
|
|
73
|
-
require_relative "smplkit/management/buffer"
|
|
74
|
-
require_relative "smplkit/management/audit"
|
|
75
|
-
require_relative "smplkit/management/jobs"
|
|
76
|
-
require_relative "smplkit/management/client"
|
|
88
|
+
require_relative "smplkit/jobs/client"
|
|
77
89
|
require_relative "smplkit/client"
|
|
78
90
|
|
|
79
91
|
require_relative "smplkit/railtie" if defined?(Rails::Railtie)
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: smplkit
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.0.
|
|
4
|
+
version: 3.0.96
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Smpl Solutions LLC
|
|
@@ -879,13 +879,18 @@ files:
|
|
|
879
879
|
- lib/smplkit/_generated/logging/spec/models/usage_list_response_spec.rb
|
|
880
880
|
- lib/smplkit/_generated/logging/spec/models/usage_resource_spec.rb
|
|
881
881
|
- lib/smplkit/_generated/logging/spec/spec_helper.rb
|
|
882
|
+
- lib/smplkit/account/client.rb
|
|
883
|
+
- lib/smplkit/account/models.rb
|
|
884
|
+
- lib/smplkit/api_support.rb
|
|
882
885
|
- lib/smplkit/audit/buffer.rb
|
|
883
886
|
- lib/smplkit/audit/categories.rb
|
|
884
887
|
- lib/smplkit/audit/client.rb
|
|
885
888
|
- lib/smplkit/audit/event_types.rb
|
|
886
889
|
- lib/smplkit/audit/events.rb
|
|
890
|
+
- lib/smplkit/audit/forwarders.rb
|
|
887
891
|
- lib/smplkit/audit/models.rb
|
|
888
892
|
- lib/smplkit/audit/resource_types.rb
|
|
893
|
+
- lib/smplkit/buffers.rb
|
|
889
894
|
- lib/smplkit/client.rb
|
|
890
895
|
- lib/smplkit/config/client.rb
|
|
891
896
|
- lib/smplkit/config/helpers.rb
|
|
@@ -901,6 +906,7 @@ files:
|
|
|
901
906
|
- lib/smplkit/generators/install_generator.rb
|
|
902
907
|
- lib/smplkit/helpers.rb
|
|
903
908
|
- lib/smplkit/http_pool.rb
|
|
909
|
+
- lib/smplkit/jobs/client.rb
|
|
904
910
|
- lib/smplkit/jobs/models.rb
|
|
905
911
|
- lib/smplkit/log_level.rb
|
|
906
912
|
- lib/smplkit/logging/adapters/base.rb
|
|
@@ -913,14 +919,12 @@ files:
|
|
|
913
919
|
- lib/smplkit/logging/normalize.rb
|
|
914
920
|
- lib/smplkit/logging/resolution.rb
|
|
915
921
|
- lib/smplkit/logging/sources.rb
|
|
916
|
-
- lib/smplkit/management/audit.rb
|
|
917
|
-
- lib/smplkit/management/buffer.rb
|
|
918
|
-
- lib/smplkit/management/client.rb
|
|
919
|
-
- lib/smplkit/management/jobs.rb
|
|
920
|
-
- lib/smplkit/management/models.rb
|
|
921
|
-
- lib/smplkit/management/types.rb
|
|
922
922
|
- lib/smplkit/metrics.rb
|
|
923
|
+
- lib/smplkit/platform/client.rb
|
|
924
|
+
- lib/smplkit/platform/models.rb
|
|
925
|
+
- lib/smplkit/platform/types.rb
|
|
923
926
|
- lib/smplkit/railtie.rb
|
|
927
|
+
- lib/smplkit/transport.rb
|
|
924
928
|
- lib/smplkit/version.rb
|
|
925
929
|
- lib/smplkit/ws.rb
|
|
926
930
|
- sig/smplkit.rbs
|
|
@@ -1,198 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Smplkit
|
|
4
|
-
module Management
|
|
5
|
-
CONTEXT_REGISTRATION_LRU_SIZE = 10_000
|
|
6
|
-
CONTEXT_BATCH_FLUSH_SIZE = 100
|
|
7
|
-
FLAG_BATCH_FLUSH_SIZE = 50
|
|
8
|
-
LOGGER_BATCH_FLUSH_SIZE = 50
|
|
9
|
-
CONFIG_BATCH_FLUSH_SIZE = 50
|
|
10
|
-
|
|
11
|
-
# Thread-safe batch buffer for context registration.
|
|
12
|
-
class ContextRegistrationBuffer
|
|
13
|
-
def initialize
|
|
14
|
-
@seen = {}
|
|
15
|
-
@pending = []
|
|
16
|
-
@lock = Mutex.new
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def observe(contexts)
|
|
20
|
-
@lock.synchronize do
|
|
21
|
-
contexts.each do |ctx|
|
|
22
|
-
cache_key = [ctx.type, ctx.key]
|
|
23
|
-
next if @seen.key?(cache_key)
|
|
24
|
-
|
|
25
|
-
@seen.shift if @seen.size >= CONTEXT_REGISTRATION_LRU_SIZE
|
|
26
|
-
@seen[cache_key] = ctx.attributes
|
|
27
|
-
@pending << { "type" => ctx.type, "key" => ctx.key, "attributes" => ctx.attributes.dup }
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
def drain
|
|
33
|
-
@lock.synchronize do
|
|
34
|
-
batch = @pending
|
|
35
|
-
@pending = []
|
|
36
|
-
batch
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
def pending_count
|
|
41
|
-
@lock.synchronize { @pending.length }
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
# Thread-safe batch buffer for flag declarations.
|
|
46
|
-
#
|
|
47
|
-
# Use +peek+ + +commit(ids)+ for the send path so a failed POST leaves
|
|
48
|
-
# declarations queued for the next attempt. +drain+ is unconditional and
|
|
49
|
-
# used only by tests/teardown.
|
|
50
|
-
class FlagRegistrationBuffer
|
|
51
|
-
def initialize
|
|
52
|
-
@seen = {}
|
|
53
|
-
@pending = []
|
|
54
|
-
@lock = Mutex.new
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
def add(declaration)
|
|
58
|
-
@lock.synchronize do
|
|
59
|
-
next if @seen.key?(declaration.id)
|
|
60
|
-
|
|
61
|
-
@seen[declaration.id] = true
|
|
62
|
-
item = { "id" => declaration.id, "type" => declaration.type, "default" => declaration.default }
|
|
63
|
-
item["service"] = declaration.service if declaration.service
|
|
64
|
-
item["environment"] = declaration.environment if declaration.environment
|
|
65
|
-
@pending << item
|
|
66
|
-
end
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
def peek
|
|
70
|
-
@lock.synchronize { @pending.dup }
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
def commit(ids)
|
|
74
|
-
return if ids.nil? || ids.empty?
|
|
75
|
-
|
|
76
|
-
committed = ids.to_set
|
|
77
|
-
@lock.synchronize { @pending.reject! { |item| committed.include?(item["id"]) } }
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
def drain
|
|
81
|
-
@lock.synchronize do
|
|
82
|
-
batch = @pending
|
|
83
|
-
@pending = []
|
|
84
|
-
batch
|
|
85
|
-
end
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
def pending_count
|
|
89
|
-
@lock.synchronize { @pending.length }
|
|
90
|
-
end
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
# Thread-safe batch buffer for config declarations. Mirrors Python's
|
|
94
|
-
# +_ConfigRegistrationBuffer+: per-config metadata is retained across
|
|
95
|
-
# flushes so post-drain deltas re-attribute correctly, and items are
|
|
96
|
-
# dedup'd per +(config_id, item_key)+ so an already-sent item is
|
|
97
|
-
# never re-sent.
|
|
98
|
-
class ConfigRegistrationBuffer
|
|
99
|
-
def initialize
|
|
100
|
-
@pending = {} # config_id -> { id:, items: {}, ...meta }
|
|
101
|
-
@meta = {} # config_id -> { service:, environment:, parent:, name:, description: }
|
|
102
|
-
@sent_items = {} # "#{config_id}::#{item_key}" -> true
|
|
103
|
-
@lock = Mutex.new
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
# Idempotent — first writer's metadata wins.
|
|
107
|
-
def declare(config_id, service:, environment:, parent: nil, name: nil, description: nil)
|
|
108
|
-
@lock.synchronize do
|
|
109
|
-
next if @meta.key?(config_id)
|
|
110
|
-
|
|
111
|
-
@meta[config_id] = {
|
|
112
|
-
service: service, environment: environment,
|
|
113
|
-
parent: parent, name: name, description: description
|
|
114
|
-
}
|
|
115
|
-
@pending[config_id] = build_entry(config_id)
|
|
116
|
-
end
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
# Queue an item declaration for an already-declared config. Items
|
|
120
|
-
# already sent in a previous +drain+ are skipped.
|
|
121
|
-
def add_item(config_id, item_key, item_type, default, description = nil)
|
|
122
|
-
@lock.synchronize do
|
|
123
|
-
next unless @meta.key?(config_id)
|
|
124
|
-
next if @sent_items.key?("#{config_id}::#{item_key}")
|
|
125
|
-
|
|
126
|
-
entry = (@pending[config_id] ||= build_entry(config_id))
|
|
127
|
-
next if entry["items"].key?(item_key)
|
|
128
|
-
|
|
129
|
-
item = { "value" => default, "type" => item_type }
|
|
130
|
-
item["description"] = description unless description.nil?
|
|
131
|
-
entry["items"][item_key] = item
|
|
132
|
-
end
|
|
133
|
-
end
|
|
134
|
-
|
|
135
|
-
# Returns and clears the pending batch; records sent items.
|
|
136
|
-
def drain
|
|
137
|
-
@lock.synchronize do
|
|
138
|
-
entries = @pending.values
|
|
139
|
-
entries.each do |entry|
|
|
140
|
-
entry["items"].each_key { |item_key| @sent_items["#{entry["id"]}::#{item_key}"] = true }
|
|
141
|
-
end
|
|
142
|
-
@pending = {}
|
|
143
|
-
entries
|
|
144
|
-
end
|
|
145
|
-
end
|
|
146
|
-
|
|
147
|
-
def pending_count
|
|
148
|
-
@lock.synchronize { @pending.size }
|
|
149
|
-
end
|
|
150
|
-
|
|
151
|
-
private
|
|
152
|
-
|
|
153
|
-
def build_entry(config_id)
|
|
154
|
-
meta = @meta[config_id]
|
|
155
|
-
entry = { "id" => config_id, "items" => {} }
|
|
156
|
-
%i[service environment parent name description].each do |k|
|
|
157
|
-
v = meta[k]
|
|
158
|
-
entry[k.to_s] = v unless v.nil?
|
|
159
|
-
end
|
|
160
|
-
entry
|
|
161
|
-
end
|
|
162
|
-
end
|
|
163
|
-
|
|
164
|
-
# Thread-safe batch buffer for logger discovery.
|
|
165
|
-
class LoggerRegistrationBuffer
|
|
166
|
-
def initialize
|
|
167
|
-
@seen = {}
|
|
168
|
-
@pending = []
|
|
169
|
-
@lock = Mutex.new
|
|
170
|
-
end
|
|
171
|
-
|
|
172
|
-
def add(source)
|
|
173
|
-
@lock.synchronize do
|
|
174
|
-
next if @seen.key?(source.name)
|
|
175
|
-
|
|
176
|
-
@seen[source.name] = source.resolved_level
|
|
177
|
-
item = { "id" => source.name, "resolved_level" => source.resolved_level&.to_s }
|
|
178
|
-
item["level"] = source.level&.to_s if source.level
|
|
179
|
-
item["service"] = source.service if source.service
|
|
180
|
-
item["environment"] = source.environment if source.environment
|
|
181
|
-
@pending << item
|
|
182
|
-
end
|
|
183
|
-
end
|
|
184
|
-
|
|
185
|
-
def drain
|
|
186
|
-
@lock.synchronize do
|
|
187
|
-
batch = @pending
|
|
188
|
-
@pending = []
|
|
189
|
-
batch
|
|
190
|
-
end
|
|
191
|
-
end
|
|
192
|
-
|
|
193
|
-
def pending_count
|
|
194
|
-
@lock.synchronize { @pending.length }
|
|
195
|
-
end
|
|
196
|
-
end
|
|
197
|
-
end
|
|
198
|
-
end
|