gitlab-labkit 2.8.0 → 3.0.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a0038ac3c9b17772bb517d4e2fc9e61ca26d05647e3de991c4899dfc867f4d88
4
- data.tar.gz: 041f4b6ee0f7257738b0bb7663adcbca06c9f520152cd7f7b8397b31ed280d7c
3
+ metadata.gz: 5c4b2288dc9341d5acd02a9ad274702ad2c44793c5760f04b6597c7404cad509
4
+ data.tar.gz: f6bc276c4452b9952dcd5e194f76d74c787ba122ae39070d35fc507aec06d444
5
5
  SHA512:
6
- metadata.gz: ee2a000a091c0eb8433911f6a0e17d7921c1477204ed9f5e5fb54a3b8d625c8361b7653134cb5231c7b78e4fdc6df74c1b3c9d92424b1a17533f35257b913115
7
- data.tar.gz: dd0a54427b6a2181bfad09efda0536ca4c0b703e2ee8182214a0ce02079f7ee207423f4e7f7d4f40f564a98d2e2d6eaeac8b4e312cf288450c2c0d8e6d146c4f
6
+ metadata.gz: fb5d89354c732b5ea0ac8579422a2fd3212e2e79f9d035ad0bdb642258710e2c7cf43abbfbd9c6b6f95d4fe190799ddbbcaf34b0b3d51ff857c0a8330e56af7f
7
+ data.tar.gz: cea073f528c655e9df4df9715a6a7a5728f13c55e75190f2ace56ca15aba59ec84ac902037125b54de0f7631fbcd03120fd1a8caad3d8854481d39a73eeb11d6
@@ -48,15 +48,68 @@ module Labkit
48
48
  begin
49
49
  super
50
50
  ensure
51
- payload[:duration] = (::Labkit::System.monotonic_time - start_time).to_f
51
+ # Fold in any connection-establishment time (DNS/TCP/TLS) measured by
52
+ # `#do_start`, so a slow connect is attributed to the request instead
53
+ # of vanishing. Counted once, on the first request of the connection.
54
+ payload[:duration] = (::Labkit::System.monotonic_time - start_time).to_f + take_connect_duration
52
55
  end
53
56
  payload[:code] = response.code
54
57
  response
55
58
  end
56
59
  end
57
60
 
61
+ # Net::HTTP establishes the connection (DNS resolution, TCP connect, TLS
62
+ # handshake) here, before any `#request` runs. With the explicit-start
63
+ # pattern (`Net::HTTP.start(host) { |http| http.request(...) }`) this happens
64
+ # entirely outside `#request`, so without instrumenting it a connection that
65
+ # hangs -- or fails with e.g. Net::OpenTimeout before any request is sent --
66
+ # would contribute nothing to external_http timing or counts.
67
+ def do_start
68
+ start_time = ::Labkit::System.monotonic_time
69
+
70
+ begin
71
+ super
72
+ rescue StandardError
73
+ # The connection failed before any request could be sent, so `#request`
74
+ # will never run to attribute this time. Emit a standalone event so the
75
+ # failure and the time spent are still visible.
76
+ ActiveSupport::Notifications.instrument(
77
+ ::Labkit::EXTERNAL_HTTP_NOTIFICATION_TOPIC, create_connect_payload
78
+ ) do |payload|
79
+ payload[:duration] = (::Labkit::System.monotonic_time - start_time).to_f
80
+ raise
81
+ end
82
+ end
83
+
84
+ @labkit_connect_duration = (::Labkit::System.monotonic_time - start_time).to_f
85
+ end
86
+ private :do_start
87
+
58
88
  private
59
89
 
90
+ def take_connect_duration
91
+ duration = @labkit_connect_duration || 0.0
92
+ @labkit_connect_duration = nil
93
+ duration
94
+ end
95
+
96
+ def create_connect_payload
97
+ {
98
+ method: nil,
99
+ host: address,
100
+ port: port,
101
+ scheme: use_ssl? ? "https" : "http",
102
+ path: nil,
103
+ query: nil,
104
+ fragment: nil
105
+ }.tap do |payload|
106
+ if proxy?
107
+ payload[:proxy_host] = proxy_address
108
+ payload[:proxy_port] = proxy_port
109
+ end
110
+ end
111
+ end
112
+
60
113
  def create_request_payload(request)
61
114
  payload = {
62
115
  method: request.method
@@ -146,7 +146,7 @@ A `Rule` is a `Data.define` value object with the following fields:
146
146
  | `match` | Hash of identifier key/value predicates that must **all** be satisfied for the rule to apply. Empty hash matches anything. See [Matchers](#matchers). |
147
147
  | `limit` | Integer request threshold per `period`. May be a callable resolved on every check. |
148
148
  | `period` | Window length in seconds. May be a callable resolved on every check. |
149
- | `action` | What the result reports when the limit is exceeded. One of `:block`, `:log`, `:allow`, `:skip`. Default `:block`. See [Actions](#actions). |
149
+ | `action` | What the result reports when the limit is exceeded. One of `:block`, `:log`, `:skip`. Default `:block`. See [Actions](#actions). |
150
150
  | `characteristics` | Array of identifier keys whose values are folded into the Redis counter key. Each unique combination gets its own counter. |
151
151
 
152
152
  Making `limit` or `period` callable is the supported pattern for
@@ -198,7 +198,7 @@ flowchart TD
198
198
  Build --> Emit[Emit calls_total + limit/period gauges]
199
199
  Emit --> Act{rule.action}
200
200
  Act -->|":log<br/>(non-terminating)"| Iter
201
- Act -->|:block or :allow| Return([Return Result])
201
+ Act -->|:block| Return([Return Result])
202
202
  Iter -->|no more rules| Unmatched[Emit calls_total<br/>rule=unmatched, action=allow]
203
203
  Unmatched --> ReturnUnmatched([Return matched=false<br/>action=:allow])
204
204
  Eval -. StandardError .-> Error[Emit errors_total<br/>log warn]
@@ -219,17 +219,12 @@ which never touch Redis:
219
219
  together and the `:log` rule cannot disable the `:block` rule. Note that a
220
220
  pure `:log`-only check still emits one `rule="unmatched"` metric entry
221
221
  because no terminating rule fired.
222
- - `:allow` — when exceeded, `Result#action` is `:allow` (rather than
223
- `:block`). Useful for "always allow this caller even if they're over the
224
- limit" cases while still observing them via metrics. Evaluation terminates
225
- on the first match.
226
222
  - `:skip` — bypass. A matching rule terminates evaluation with
227
223
  `Result#action` `:allow` **without any Redis operation**: nothing is
228
224
  counted, so `limit`, `period`, `characteristics`, and `count_distinct` are
229
225
  inert and the result carries no `info` (`to_response_headers` is `{}`).
230
226
  The match is still observable via `calls_total{action="skip"}`. Use this
231
- for bypasses that don't need a counter; use `:allow` only when you want
232
- the bypassed traffic counted.
227
+ for bypasses.
233
228
 
234
229
  ### Redis keys
235
230
 
@@ -8,9 +8,9 @@ module Labkit
8
8
  # action - the outcome: what the caller should do
9
9
  # :block = rule matched, exceeded, rule configured to block
10
10
  # :log = rule matched, exceeded, rule configured to log only
11
- # :allow = rule matched but count within limit, rule configured to allow,
12
- # rule configured to skip (bypass, nothing counted),
13
- # no rule matched, or error (fail-open)
11
+ # :allow = rule matched but count within limit, rule configured
12
+ # to skip (bypass, nothing counted), no rule matched,
13
+ # or error (fail-open)
14
14
  # The rule's configured action is available via rule.action.
15
15
  # rule - the matched Rule object (nil when matched? is false)
16
16
  # error? - true if Redis was unavailable; result fails open (exceeded? is false)
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Labkit
4
4
  module RateLimit
5
- KNOWN_ACTIONS = %i[block log allow skip].freeze
5
+ KNOWN_ACTIONS = %i[block log skip].freeze
6
6
  RULE_NAME_PATTERN = /\A[a-z0-9_]+\z/
7
7
  RULE_NAME_MAX_LENGTH = 64
8
8
 
@@ -13,9 +13,7 @@ module Labkit
13
13
  # limit - request threshold; may be a callable (resolved per check)
14
14
  # period - window in seconds; may be a callable (resolved per check)
15
15
  # action - :block (enforce), :log (count and log only, do not block,
16
- # evaluation continues to subsequent rules), :allow
17
- # (count but always permit; terminates evaluation on match
18
- # regardless of whether the limit was exceeded), or :skip
16
+ # evaluation continues to subsequent rules), or :skip
19
17
  # (bypass: permit and terminate evaluation on match without
20
18
  # counting; performs no Redis operation, so limit, period,
21
19
  # characteristics, and count_distinct are inert)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gitlab-labkit
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.8.0
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Newdigate