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 +4 -4
- data/.version +1 -1
- data/CHANGELOG.md +22 -0
- data/Gemfile.lock +1 -1
- data/README.md +26 -0
- data/lib/atlas_rb/metrics.rb +71 -0
- data/lib/atlas_rb.rb +1 -0
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 57da54874f04fe2d2b07757c8c062fe5a4e95aae8d843de69ed7bd53158b8122
|
|
4
|
+
data.tar.gz: af25098d8000917fac7e65121fc575dd38460ed23c2515e6309d2d230c9389ce
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 228ce5a5c9c2746628bea89760fd5b623d017a3511e2d8f59ce22401aa58499a2e82500da0fd76ba12dacd5e3d5fd772694f717b7312e98b0c2b8fec43c94ca2
|
|
7
|
+
data.tar.gz: 3b92e9cf2b59e766276a7654fa2769d5339b9b511f146aa429692b8f7d84dfa3a96b5575659b6ee923d64bc3b08bc1291f8245de75922b419ba9b276629a7043
|
data/.version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
1.27.
|
|
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
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.
|
|
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
|