atlas_rb 1.27.1 → 1.27.3

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: 2c1b0723d54145c8be9868a1849502cf80adbc1a30b2f7b1ee39aadbfa1a2f3b
4
- data.tar.gz: 7ab2bb5a662b02dd48275e645f9c6b3c1226d6bc995231766bd5a4252f17b25a
3
+ metadata.gz: 57da54874f04fe2d2b07757c8c062fe5a4e95aae8d843de69ed7bd53158b8122
4
+ data.tar.gz: af25098d8000917fac7e65121fc575dd38460ed23c2515e6309d2d230c9389ce
5
5
  SHA512:
6
- metadata.gz: 64f43d675ad66dac85657c0460702f53f95c99760e7a44ce6f0dec019e375f41b197c214ca3dc4d89a94a1e0b829fa9d377fd4dd9432fe68cdc53d9aa490e38e
7
- data.tar.gz: dfc0ade69d92b8b100698091f6ec22d90eb428769bb61aebdc79a9e842840036bc45875bc330531be335d5a11459c823ff13a1ccd78e1b143b11009f083ca54b
6
+ metadata.gz: 228ce5a5c9c2746628bea89760fd5b623d017a3511e2d8f59ce22401aa58499a2e82500da0fd76ba12dacd5e3d5fd772694f717b7312e98b0c2b8fec43c94ca2
7
+ data.tar.gz: 3b92e9cf2b59e766276a7654fa2769d5339b9b511f146aa429692b8f7d84dfa3a96b5575659b6ee923d64bc3b08bc1291f8245de75922b419ba9b276629a7043
data/.version CHANGED
@@ -1 +1 @@
1
- 1.27.1
1
+ 1.27.3
data/CHANGELOG.md CHANGED
@@ -1,5 +1,27 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.27.3
4
+
5
+ ### Changed — `Metrics.latency` documentation
6
+
7
+ Atlas 0.6.227 times each request from the top of its Rack stack, the same span
8
+ as `x-runtime`, rather than the controller action alone. The YARD and README
9
+ now say so. No code changed; against an older Atlas the figures are still
10
+ action-only.
11
+
12
+ ## 1.27.2
13
+
14
+ Requires an Atlas that serves `GET /metrics/latency`.
15
+
16
+ ### Added — `AtlasRb::Metrics.latency`
17
+
18
+ Reads Atlas's own request latency for a window of up to 120 minutes: calls,
19
+ 5xx count, mean and approximate p50/p95/p99, and the slowest actions. Sent
20
+ with the acting NUID's signed assertion, which must name an admin. A
21
+ 5-second deadline, no retry and a fresh socket per call. Raises
22
+ `BackendUnavailableError` when Atlas's Redis is down and `ResourceError` on
23
+ any other non-200.
24
+
3
25
  ## 1.27.1
4
26
 
5
27
  Requires an Atlas that serves `GET /health` and the `backend_unavailable`
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- atlas_rb (1.27.1)
4
+ atlas_rb (1.27.3)
5
5
  faraday (~> 2.7)
6
6
  faraday-follow_redirects (~> 0.3.0)
7
7
  faraday-multipart (~> 1)
data/README.md CHANGED
@@ -857,6 +857,32 @@ It is not a `ResourceError`, which hosts treat as a refusal of the request.
857
857
  A streaming download (`Blob.content`, `Blob.version_content`) cannot raise
858
858
  this: its body has already gone to your block. Check the returned `status`.
859
859
 
860
+ ### Atlas's own latency
861
+
862
+ `AtlasRb::Metrics.latency` reports how long Atlas took to serve its own
863
+ requests over a recent window. Atlas gates it to admins and `:system`, so
864
+ `nuid` must name an admin:
865
+
866
+ ```ruby
867
+ latency = AtlasRb::Metrics.latency(minutes: 60, nuid: current_user.nuid)
868
+ latency["calls"] # => 18402
869
+ latency["server_errors"] # => 3
870
+ latency["p95_ms"] # => 98
871
+ latency["slowest_actions"].first # => { "action" => "works#mods", "calls" => 912, "p95_ms" => 188 }
872
+ ```
873
+
874
+ Atlas times each request from when it enters Atlas's Rack stack until the app
875
+ returns the response, the same span as the `x-runtime` header. The figures
876
+ include time a request waited inside Atlas behind concurrent ones. They leave
877
+ out time queued for a Puma thread, the network, and your own waiting. If you
878
+ also time your Atlas calls, the difference is time spent on your side. The percentiles are
879
+ interpolated from histogram buckets, so they are approximate.
880
+
881
+ Like `Health.read`, it has a 5-second deadline and no retry. It raises
882
+ `BackendUnavailableError` (with `dependency == "cache"`) when Atlas's Redis is
883
+ down, `ResourceError` on any other non-200 such as a `403`, and `Faraday`
884
+ errors when nothing answers.
885
+
860
886
  ## End-to-end example
861
887
 
862
888
  JSON responses come back as `AtlasRb::Mash` (a `Hashie::Mash` subclass), so
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AtlasRb
4
+ # Atlas's own operational figures. Admin- or `:system`-gated in Atlas.
5
+ class Metrics
6
+ extend AtlasRb::FaradayHelper
7
+
8
+ # Seconds to wait for a socket to open.
9
+ OPEN_TIMEOUT = 2
10
+
11
+ # Seconds to wait for the report. It reads at most 120 small Redis hashes,
12
+ # so a slower answer means Atlas is struggling, and an admin page should
13
+ # not wait on it.
14
+ READ_TIMEOUT = 5
15
+
16
+ # How long Atlas took to serve its own requests (`GET /metrics/latency`).
17
+ #
18
+ # Measured inside Atlas, from when a request enters its Rack stack until
19
+ # the app returns the response — the same span as the `x-runtime` header.
20
+ # So it includes time a request spent waiting inside Atlas behind
21
+ # concurrent ones, and leaves out time queued for a Puma thread, the
22
+ # network, and the caller's own waiting. A caller that also times its
23
+ # Atlas calls can subtract to see how much of its wait was its own. The
24
+ # percentiles are interpolated from histogram buckets, so they are
25
+ # approximate.
26
+ #
27
+ # No retry, and a fresh socket per call: like {AtlasRb::Health.read}, it is
28
+ # polled rarely and should fail fast rather than hide a struggling Atlas.
29
+ #
30
+ # @param minutes [Integer] the window, 1 to 120. Atlas clamps it.
31
+ # @param nuid [String, nil] the acting NUID, signed into the assertion
32
+ # `sub`. It must name an admin; falls through to
33
+ # {AtlasRb.config#default_nuid}.
34
+ # @param on_behalf_of [String, nil] optional NUID carried as a signed `obo`
35
+ # claim.
36
+ # @return [AtlasRb::Mash] `window_minutes`, `calls`, `server_errors`,
37
+ # `mean_ms`, `p50_ms`, `p95_ms`, `p99_ms` (Integer, or nil with no calls),
38
+ # and `slowest_actions`, an Array of `action` / `calls` / `p95_ms`.
39
+ # @raise [AtlasRb::BackendUnavailableError] when Atlas answers that Redis,
40
+ # which holds the figures, is down (`dependency == "cache"`).
41
+ # @raise [AtlasRb::ResourceError] on any other non-200, notably a `403`
42
+ # for a caller who is not an admin.
43
+ # @raise [Faraday::ConnectionFailed, Faraday::TimeoutError] when Atlas does
44
+ # not answer at all.
45
+ #
46
+ # @example
47
+ # latency = AtlasRb::Metrics.latency(minutes: 15, nuid: current_user.nuid)
48
+ # latency.p95_ms # => 98
49
+ def self.latency(minutes: 60, nuid: nil, on_behalf_of: nil)
50
+ resp = metrics_connection(nuid, on_behalf_of).get("/metrics/latency", minutes: minutes)
51
+ return AtlasRb::Mash.new(JSON.parse(resp.body)) if resp.status == 200
52
+
53
+ raise AtlasRb::ResourceError.new("#{request_target(resp)} → #{resp.status}: #{resp.body}", response: resp)
54
+ end
55
+
56
+ class << self
57
+ private
58
+
59
+ def metrics_connection(nuid, on_behalf_of)
60
+ headers = auth_headers(nuid, on_behalf_of).merge("Content-Type" => "application/json")
61
+ Faraday.new(url: ENV.fetch("ATLAS_URL", nil), headers: headers) do |f|
62
+ f.options.open_timeout = OPEN_TIMEOUT
63
+ f.options.timeout = READ_TIMEOUT
64
+ instrument(f)
65
+ f.use AtlasRb::Middleware::RaiseOnBackendUnavailable
66
+ f.adapter :net_http
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
data/lib/atlas_rb.rb CHANGED
@@ -48,6 +48,7 @@ require_relative "atlas_rb/system/work"
48
48
  require_relative "atlas_rb/audit_event"
49
49
  require_relative "atlas_rb/maintenance"
50
50
  require_relative "atlas_rb/health"
51
+ require_relative "atlas_rb/metrics"
51
52
 
52
53
  # Ruby client for the Atlas API — Northeastern University's institutional
53
54
  # digital repository.
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: atlas_rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.27.1
4
+ version: 1.27.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Cliff
@@ -173,6 +173,7 @@ files:
173
173
  - lib/atlas_rb/health.rb
174
174
  - lib/atlas_rb/maintenance.rb
175
175
  - lib/atlas_rb/mash.rb
176
+ - lib/atlas_rb/metrics.rb
176
177
  - lib/atlas_rb/middleware/raise_on_backend_unavailable.rb
177
178
  - lib/atlas_rb/middleware/raise_on_read_error.rb
178
179
  - lib/atlas_rb/middleware/raise_on_read_only_mode.rb