async-tools 0.2.1 → 0.2.2
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/Gemfile.lock +1 -1
- data/lib/async/app/component.rb +21 -0
- data/lib/async/app/injector.rb +10 -0
- data/lib/async/app/metrics/ruby_runtime_monitor.rb +25 -0
- data/lib/async/app/metrics/serializer.rb +24 -0
- data/lib/async/app/metrics/server.rb +33 -0
- data/lib/async/app/metrics/store.rb +17 -0
- data/lib/async/app.rb +16 -35
- data/lib/async/tools/version.rb +1 -1
- metadata +7 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8b3b08f9b120bebf744df3e7c0da6e2cb7c8d4c5acb01458c25f8be8ff7588fa
|
4
|
+
data.tar.gz: 7c02d0bfce7a3bcb21b8ac8b2f4a8aec4bfad5a12233141b7d1d73b139c08684
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 496680113c44a54745da6846bca478f426454eaa34c125de569205c9f5fe3bc82ec6fe53589f8c86c0b1222361ec949c7938baa64b2be0246a15da280ca8f30a
|
7
|
+
data.tar.gz: 14d6d23403ede1040d74e68590ad0572e1c01b402ff6d7d0ff25dfb11c6f0f7a187b894c5681772e7828c88a8ba5f2e95751a3bce58ba9d9dc2aa14c31078e67
|
data/Gemfile.lock
CHANGED
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Async::App::Component
|
4
|
+
def self.included(base)
|
5
|
+
base.extend(Async::App::Injector)
|
6
|
+
base.inject(:bus)
|
7
|
+
|
8
|
+
base.include(Async::Logger)
|
9
|
+
|
10
|
+
strict = Dry.Types::Strict
|
11
|
+
|
12
|
+
string_like = (strict::String | strict::Symbol).constructor(&:to_s)
|
13
|
+
kv = strict::Hash.map(string_like, strict::String)
|
14
|
+
|
15
|
+
base.const_set(:T, Module.new do
|
16
|
+
include Dry.Types
|
17
|
+
const_set(:StringLike, string_like)
|
18
|
+
const_set(:KV, kv)
|
19
|
+
end)
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Async::App::Metrics::RubyRuntimeMonitor
|
4
|
+
include Async::Logger
|
5
|
+
|
6
|
+
INTERVAL = 2
|
7
|
+
|
8
|
+
def run
|
9
|
+
Async::Timer.new(INTERVAL, run_on_start: true, on_error: ->(e) { warn(e) }) do
|
10
|
+
fibers = ObjectSpace.each_object(Fiber)
|
11
|
+
threads = ObjectSpace.each_object(Thread)
|
12
|
+
ractors = ObjectSpace.each_object(Ractor)
|
13
|
+
|
14
|
+
yield({
|
15
|
+
ruby_fibers: { value: fibers.count },
|
16
|
+
ruby_fibers_active: { value: fibers.count(&:alive?) },
|
17
|
+
ruby_threads: { value: threads.count },
|
18
|
+
ruby_threads_active: { value: threads.count(&:alive?) },
|
19
|
+
ruby_ractors: { value: ractors.count },
|
20
|
+
ruby_memory: { value: GetProcessMem.new.bytes.to_s("F"), suffix: "bytes" }
|
21
|
+
})
|
22
|
+
end
|
23
|
+
info { "Started" }
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Async::App::Metrics::Serializer
|
4
|
+
def initialize(prefix:)
|
5
|
+
@prefix = prefix
|
6
|
+
end
|
7
|
+
|
8
|
+
def serialize(metrics)
|
9
|
+
metrics.flat_map { metric_line(_1) }
|
10
|
+
.compact
|
11
|
+
.join("\n")
|
12
|
+
.then { "#{_1}\n" }
|
13
|
+
end
|
14
|
+
|
15
|
+
def metric_name(value) = "#{@prefix}_#{value[:name]}_#{value[:suffix]}"
|
16
|
+
|
17
|
+
def metric_labels(value) = value[:labels].map { |tag, tag_value| "#{tag}=#{tag_value.to_s.inspect}" }.join(",")
|
18
|
+
|
19
|
+
def metric_line(value)
|
20
|
+
labels = metric_labels(value)
|
21
|
+
|
22
|
+
"#{metric_name(value)}{#{labels}} #{value[:value]}" if value.key?(:value)
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Async::App::Metrics::Server
|
4
|
+
include Async::Logger
|
5
|
+
|
6
|
+
PATHS = ["/metrics", "/metrics/"].freeze
|
7
|
+
|
8
|
+
def initialize(prefix:, port: 8080)
|
9
|
+
@prefix = prefix
|
10
|
+
@port = port
|
11
|
+
end
|
12
|
+
|
13
|
+
def run
|
14
|
+
Async::App::Metrics::RubyRuntimeMonitor.new.run { update_metrics(_1) }
|
15
|
+
|
16
|
+
endpoint = Async::HTTP::Endpoint.parse("http://0.0.0.0:#{@port}")
|
17
|
+
Async { Async::HTTP::Server.new(self, endpoint).run }
|
18
|
+
info { "Started on #{endpoint.url}" }
|
19
|
+
end
|
20
|
+
|
21
|
+
def call(request)
|
22
|
+
return Protocol::HTTP::Response[404, {}, ["Not found"]] unless PATHS.include?(request.path)
|
23
|
+
|
24
|
+
Protocol::HTTP::Response[200, {}, serializer.serialize(metrics_store)]
|
25
|
+
end
|
26
|
+
|
27
|
+
def update_metrics(metrics) = metrics.each { metrics_store.set(_1, **_2) }
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def metrics_store = @metrics_store ||= Async::App::Metrics::Store.new
|
32
|
+
def serializer = @serializer ||= Async::App::Metrics::Serializer.new(prefix: @prefix)
|
33
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Async::App::Metrics::Store
|
4
|
+
include Enumerable
|
5
|
+
|
6
|
+
def set(name, value:, suffix: "total", **labels)
|
7
|
+
key = [name, labels]
|
8
|
+
counters[key] ||= { name:, labels:, suffix:, value: }
|
9
|
+
counters[key].merge!(value:)
|
10
|
+
end
|
11
|
+
|
12
|
+
def each(&) = counters.values.each(&)
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def counters = @counters ||= {}
|
17
|
+
end
|
data/lib/async/app.rb
CHANGED
@@ -1,52 +1,26 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
class Async::App
|
4
|
-
|
5
|
-
|
6
|
-
module Injector
|
7
|
-
def inject(name)
|
8
|
-
define_method(name) do
|
9
|
-
$__ASYNC_APP.container[name]
|
10
|
-
end
|
11
|
-
private name
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
module Component
|
16
|
-
def self.included(base)
|
17
|
-
base.extend(Injector)
|
18
|
-
base.inject(:bus)
|
4
|
+
extend Async::App::Injector
|
19
5
|
|
20
|
-
base.include(Async::Logger)
|
21
|
-
|
22
|
-
strict = Dry.Types::Strict
|
23
|
-
|
24
|
-
string_like = (strict::String | strict::Symbol).constructor(&:to_s)
|
25
|
-
kv = strict::Hash.map(string_like, strict::String)
|
26
|
-
|
27
|
-
base.const_set(:T, Module.new do
|
28
|
-
include Dry.Types
|
29
|
-
const_set(:StringLike, string_like)
|
30
|
-
const_set(:KV, kv)
|
31
|
-
end)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
extend Injector
|
36
6
|
include Async::Logger
|
37
7
|
|
38
8
|
inject :bus
|
39
9
|
|
10
|
+
# rubocop:disable Style/GlobalVars
|
40
11
|
def initialize
|
41
12
|
raise "only one instance of #{self.class} is allowed" if $__ASYNC_APP
|
42
13
|
|
43
14
|
$__ASYNC_APP = self
|
44
|
-
|
45
|
-
container.register(:bus, Async::Bus.new(:__async_app))
|
15
|
+
@task = Async::Task.current
|
46
16
|
|
47
17
|
set_traps!
|
48
|
-
|
49
|
-
|
18
|
+
{
|
19
|
+
bus: Async::Bus.new(app_name),
|
20
|
+
**container_config
|
21
|
+
}.each { container.register(_1, _2) }
|
22
|
+
|
23
|
+
start_metrics_server!
|
50
24
|
run!
|
51
25
|
info { "Started" }
|
52
26
|
rescue StandardError => e
|
@@ -59,6 +33,7 @@ class Async::App
|
|
59
33
|
def container = @container ||= Dry::Container.new
|
60
34
|
def run! = nil
|
61
35
|
def container_config = {}
|
36
|
+
def app_name = :async_app
|
62
37
|
|
63
38
|
def stop
|
64
39
|
@task&.stop
|
@@ -82,4 +57,10 @@ class Async::App
|
|
82
57
|
fatal { "Forced exit" }
|
83
58
|
exit(1)
|
84
59
|
end
|
60
|
+
|
61
|
+
def start_metrics_server!
|
62
|
+
Metrics::Server.new(prefix: app_name).tap(&:run).tap do |server|
|
63
|
+
bus.subscribe("metrics.updated") { server.update_metrics(_1) }
|
64
|
+
end
|
65
|
+
end
|
85
66
|
end
|
data/lib/async/tools/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: async-tools
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gleb Sinyavskiy
|
@@ -61,6 +61,12 @@ files:
|
|
61
61
|
- bin/console
|
62
62
|
- bin/setup
|
63
63
|
- lib/async/app.rb
|
64
|
+
- lib/async/app/component.rb
|
65
|
+
- lib/async/app/injector.rb
|
66
|
+
- lib/async/app/metrics/ruby_runtime_monitor.rb
|
67
|
+
- lib/async/app/metrics/serializer.rb
|
68
|
+
- lib/async/app/metrics/server.rb
|
69
|
+
- lib/async/app/metrics/store.rb
|
64
70
|
- lib/async/bus.rb
|
65
71
|
- lib/async/channel.rb
|
66
72
|
- lib/async/logger.rb
|