nexaas-queue_time 0.2.0 → 0.3.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 +4 -4
- data/CHANGELOG.md +16 -25
- data/lib/nexaas/queue_time/middleware.rb +35 -13
- data/lib/nexaas/queue_time/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 87997f283ea190bbdcba83290a11d23dbc446db1a11c32d48b51d8b3bc110219
|
4
|
+
data.tar.gz: 57746b20d94c1ddd326b405906ba6dfc887089cb3f43c66d89e6d9131beec209
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ecb3f250ee9abb4caa347d1209e2696f89b4d2e4a977d11a5dd109d007d861ee8f0739d1792e693c213ce0487026974b3e0fccfab7705ec52d4f046112a59d63
|
7
|
+
data.tar.gz: 16467b32806ef5813cf070d4efe9d86171022caab30c2ecbd407e694ec0e24f1df8352f386172106785976b204d9ae954b921d52da38e43aebf28ebe7c598a10
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,21 @@
|
|
2
2
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
4
4
|
|
5
|
+
## [0.3.0] - 2019-07-01
|
6
|
+
|
7
|
+
### Added
|
8
|
+
|
9
|
+
- Document middleware class
|
10
|
+
- Test for header pattern before calculating `queue_time`
|
11
|
+
|
12
|
+
### Changed
|
13
|
+
|
14
|
+
- Do not calculate `queue_time` if header is not present
|
15
|
+
|
16
|
+
### Fixed
|
17
|
+
|
18
|
+
- Use `String =~` instead of `String#match?` due to Ruby 2.3
|
19
|
+
|
5
20
|
## [0.2.0] - 2019-06-28
|
6
21
|
|
7
22
|
### Fixed
|
@@ -15,28 +30,4 @@ All notable changes to this project will be documented in this file.
|
|
15
30
|
- Initial implementation of the gem
|
16
31
|
|
17
32
|
|
18
|
-
[
|
19
|
-
[5.4.2]: https://github.com/kickstarter/rack-attack/compare/v5.4.1...v5.4.2/
|
20
|
-
[5.4.1]: https://github.com/kickstarter/rack-attack/compare/v5.4.0...v5.4.1/
|
21
|
-
[5.4.0]: https://github.com/kickstarter/rack-attack/compare/v5.3.2...v5.4.0/
|
22
|
-
[5.3.2]: https://github.com/kickstarter/rack-attack/compare/v5.3.1...v5.3.2/
|
23
|
-
[5.3.1]: https://github.com/kickstarter/rack-attack/compare/v5.3.0...v5.3.1/
|
24
|
-
[5.3.0]: https://github.com/kickstarter/rack-attack/compare/v5.2.0...v5.3.0/
|
25
|
-
[5.2.0]: https://github.com/kickstarter/rack-attack/compare/v5.1.0...v5.2.0/
|
26
|
-
[5.1.0]: https://github.com/kickstarter/rack-attack/compare/v5.0.1...v5.1.0/
|
27
|
-
[5.0.1]: https://github.com/kickstarter/rack-attack/compare/v5.0.0...v5.0.1/
|
28
|
-
[5.0.0]: https://github.com/kickstarter/rack-attack/compare/v4.4.1...v5.0.0/
|
29
|
-
[4.4.1]: https://github.com/kickstarter/rack-attack/compare/v4.4.0...v4.4.1/
|
30
|
-
[4.4.0]: https://github.com/kickstarter/rack-attack/compare/v4.3.1...v4.4.0/
|
31
|
-
[4.3.1]: https://github.com/kickstarter/rack-attack/compare/v4.3.0...v4.3.1/
|
32
|
-
[4.3.0]: https://github.com/kickstarter/rack-attack/compare/v4.2.0...v4.3.0/
|
33
|
-
[4.2.0]: https://github.com/kickstarter/rack-attack/compare/v4.1.1...v4.2.0/
|
34
|
-
[4.1.1]: https://github.com/kickstarter/rack-attack/compare/v4.1.0...v4.1.1/
|
35
|
-
[4.1.0]: https://github.com/kickstarter/rack-attack/compare/v4.0.1...v4.1.0/
|
36
|
-
[4.0.1]: https://github.com/kickstarter/rack-attack/compare/v4.0.0...v4.0.1/
|
37
|
-
[4.0.0]: https://github.com/kickstarter/rack-attack/compare/v3.0.0...v4.0.0/
|
38
|
-
[3.0.0]: https://github.com/kickstarter/rack-attack/compare/v2.3.0...v3.0.0/
|
39
|
-
[2.3.0]: https://github.com/kickstarter/rack-attack/compare/v2.2.1...v2.3.0/
|
40
|
-
[2.2.1]: https://github.com/kickstarter/rack-attack/compare/v2.2.0...v2.2.1/
|
41
|
-
[2.2.0]: https://github.com/kickstarter/rack-attack/compare/v2.1.1...v2.2.0/
|
42
|
-
|
33
|
+
[0.2.0]: https://github.com/myfreecomm/nexaas-queue_time/compare/v0.1.0...v0.2.0/
|
@@ -4,40 +4,62 @@ require 'datadog/statsd'
|
|
4
4
|
|
5
5
|
module Nexaas
|
6
6
|
module QueueTime
|
7
|
+
# This middleware calculates the time a request has been waiting
|
8
|
+
# in the queue before being served by the application server.
|
9
|
+
#
|
10
|
+
# It requires the header `X_REQUEST_START`. This header contains
|
11
|
+
# the timestamp of when the request first apperead in the stack.
|
12
|
+
# This header is usually set by a LoadBalancer, Reverse Proxy or Router.
|
13
|
+
#
|
14
|
+
# The format of the header **must** match:
|
15
|
+
# `t=TIMESTAMP`, where TIMESTAMP is the unix timestamp.
|
16
|
+
# This format is supported by APMs such as New Relic and Scout
|
7
17
|
class Middleware
|
8
18
|
METRIC_NAME = 'request.queue_time'
|
19
|
+
HEADER_FORMAT_PATTERN = /
|
20
|
+
^ # Beginning of line
|
21
|
+
t= #
|
22
|
+
\d+ # At least 1 digit
|
23
|
+
\.? # Optionally a dot may be used for fractional timestamps
|
24
|
+
\d* # Optionally more digits after the dot
|
25
|
+
$ # End of line
|
26
|
+
/x
|
9
27
|
|
10
28
|
def initialize(app)
|
11
29
|
@app = app
|
12
30
|
end
|
13
31
|
|
14
32
|
def call(env)
|
15
|
-
|
16
|
-
|
17
|
-
|
33
|
+
request_start_header = env['HTTP_X_REQUEST_START']
|
34
|
+
if request_start_header && request_start_header =~ HEADER_FORMAT_PATTERN
|
35
|
+
left_queue_at = Time.now.to_f
|
36
|
+
metric = calculate_queue_time_in_ms(left_queue_at, request_start_header)
|
37
|
+
send_metric(metric)
|
38
|
+
end
|
18
39
|
|
19
40
|
@app.call(env)
|
20
41
|
end
|
21
42
|
|
22
43
|
private
|
23
44
|
|
24
|
-
def
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
entered_queue = extract_timestamp(entered_queue)
|
29
|
-
(left_queue - entered_queue.to_f) * 1000
|
45
|
+
def calculate_queue_time_in_ms(left_queue_at, request_start_header)
|
46
|
+
entered_queue_at = extract_timestamp(request_start_header)
|
47
|
+
(left_queue_at - entered_queue_at.to_f) * 1000
|
30
48
|
end
|
31
49
|
|
32
|
-
# The header actually comes as `t=1234567890`,
|
33
|
-
# so we need to extract the timestamp.
|
34
50
|
def extract_timestamp(entered_queue)
|
35
51
|
entered_queue.delete('t=')
|
36
52
|
end
|
37
53
|
|
54
|
+
# By default, Datadog::Statsd opens a UDP connection with a given host and port.
|
55
|
+
# Instead, we are giving it a socket path so it communicates with the statsd server via UDS.
|
56
|
+
#
|
57
|
+
# This approach is easier to setup in containerized environments since all it requires
|
58
|
+
# is the path to the socket file instead of the host address.
|
59
|
+
#
|
60
|
+
# UDS also performs better than UDP,
|
61
|
+
# although the app would need to receive huge traffic to actually feel the difference.
|
38
62
|
def send_metric(metric)
|
39
|
-
return unless metric
|
40
|
-
|
41
63
|
Datadog::Statsd.open(nil, nil, socket_path: '/var/run/datadog/dsd.socket') do |statsd|
|
42
64
|
statsd.timing(METRIC_NAME, metric.to_i, sample_rate: 1)
|
43
65
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nexaas-queue_time
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lucas Mansur
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-07-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: dogstatsd-ruby
|