async-tools 0.2.9 → 0.2.10
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/lib/async/app/autoload_component.rb +5 -0
- data/lib/async/app/component.rb +15 -1
- data/lib/async/app/event_logger.rb +1 -1
- data/lib/async/app/injector.rb +1 -1
- data/lib/async/app/metrics/components_metrics_collector.rb +21 -0
- data/lib/async/app/metrics/ruby_runtime_metrics_collector.rb +7 -8
- data/lib/async/app/timer_component.rb +46 -0
- data/lib/async/app/{web_server → web_apps}/health_app.rb +4 -4
- data/lib/async/app/{web_server → web_apps}/metrics_app/serializer.rb +1 -1
- data/lib/async/app/{web_server → web_apps}/metrics_app/store.rb +1 -1
- data/lib/async/app/{web_server → web_apps}/metrics_app.rb +7 -4
- data/lib/async/app/web_component.rb +15 -0
- data/lib/async/app/web_server.rb +24 -7
- data/lib/async/app.rb +39 -39
- data/lib/async/timer.rb +6 -4
- data/lib/async/tools/version.rb +1 -1
- data/lib/async/tools.rb +3 -2
- metadata +10 -7
- data/lib/async/app/web_server/router.rb +0 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0d1ee91075ee99708de1e43d75c7184d9a23c79a0cf36291d91d7ede9314d22d
|
4
|
+
data.tar.gz: b49e3539aadec63fa3aeed3c3e95bb6bbeca1ef33ef3487bf406b8a28430941d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 02e5dce453e331558d760ff45769f466192e1b95963373e23cd9668c364bc131902f3d09457363b987308326def15e841651c3311b09d1a1878c61fba03b595d
|
7
|
+
data.tar.gz: ab0d8f31349e0514d14ff1c232072c530658db77c6302e5af13238b8bb25cc96226e3b8d7075367653c62095dcf1ca9e64b2120a234364119ed3310e126c2a7f
|
data/Gemfile.lock
CHANGED
data/lib/async/app/component.rb
CHANGED
@@ -7,5 +7,19 @@ module Async::App::Component
|
|
7
7
|
base.include(Async::Logger)
|
8
8
|
end
|
9
9
|
|
10
|
-
def
|
10
|
+
def start!
|
11
|
+
init!
|
12
|
+
after_init
|
13
|
+
run!
|
14
|
+
after_run
|
15
|
+
end
|
16
|
+
|
17
|
+
def init! = nil
|
18
|
+
def run! = info { "Started" }
|
19
|
+
|
20
|
+
# TODO: unsubscribe from everything on stop
|
21
|
+
def stop! = info { "Stopped" }
|
22
|
+
|
23
|
+
def after_init = nil
|
24
|
+
def after_run = nil
|
11
25
|
end
|
data/lib/async/app/injector.rb
CHANGED
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Async::App::Metrics::ComponentsMetricsCollector
|
4
|
+
include Async::App::TimerComponent
|
5
|
+
include Async::App::AutoloadComponent
|
6
|
+
|
7
|
+
def on_tick = bus.publish("metrics.updated", metrics)
|
8
|
+
def interval = 5
|
9
|
+
def run_on_start = true
|
10
|
+
def on_error(exception) = warn { exception }
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def metrics
|
15
|
+
{
|
16
|
+
async_app_components: { value: Async::App.instance.components.count },
|
17
|
+
async_app_autoloadable_components: { value: Async::App.instance.autoloadable_components.count },
|
18
|
+
async_app_timer_components: { value: Async::App.instance.timer_components.count }
|
19
|
+
}
|
20
|
+
end
|
21
|
+
end
|
@@ -1,16 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
class Async::App::Metrics::RubyRuntimeMetricsCollector
|
4
|
-
include Async::App::
|
4
|
+
include Async::App::TimerComponent
|
5
|
+
include Async::App::AutoloadComponent
|
5
6
|
|
6
|
-
|
7
|
+
def on_tick = bus.publish("metrics.updated", metrics)
|
8
|
+
def interval = 5
|
9
|
+
def run_on_start = true
|
10
|
+
def on_error(exception) = warn { exception }
|
7
11
|
|
8
|
-
|
9
|
-
Async::Timer.new(INTERVAL, run_on_start: true, on_error: ->(e) { warn(e) }) do
|
10
|
-
bus.publish("metrics.updated", metrics)
|
11
|
-
end
|
12
|
-
info { "Started" }
|
13
|
-
end
|
12
|
+
private
|
14
13
|
|
15
14
|
def metrics
|
16
15
|
fibers = ObjectSpace.each_object(Fiber)
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Async::App::TimerComponent
|
4
|
+
def self.included(base)
|
5
|
+
base.include(Async::App::Component)
|
6
|
+
base.include(InstanceMethods)
|
7
|
+
end
|
8
|
+
|
9
|
+
module InstanceMethods
|
10
|
+
def init!
|
11
|
+
super
|
12
|
+
@timer = Async::Timer.new(run_on_start:, start: false, on_error: method(:on_error)) { tick! }
|
13
|
+
end
|
14
|
+
|
15
|
+
def run!
|
16
|
+
return if @timer.active?
|
17
|
+
|
18
|
+
@timer.start(interval)
|
19
|
+
info { "Started. Interval = #{interval}" }
|
20
|
+
end
|
21
|
+
|
22
|
+
def stop!
|
23
|
+
@timer&.stop
|
24
|
+
super
|
25
|
+
end
|
26
|
+
|
27
|
+
# TimerComponent - specific methods
|
28
|
+
def tick!
|
29
|
+
debug { "Started" }
|
30
|
+
on_tick
|
31
|
+
debug { "Finished" }
|
32
|
+
end
|
33
|
+
|
34
|
+
def restart!
|
35
|
+
@timer.restart(interval)
|
36
|
+
info { "Restarted. Polling interval=#{interval}" }
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def interval = raise NotImplementedError
|
42
|
+
def run_on_start = raise NotImplementedError
|
43
|
+
def on_tick = raise NotImplementedError
|
44
|
+
def on_error(exception) = raise exception
|
45
|
+
end
|
46
|
+
end
|
@@ -1,13 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
class Async::App::
|
4
|
-
include Async::App::
|
3
|
+
class Async::App::WebApps::HealthApp
|
4
|
+
include Async::App::WebComponent
|
5
|
+
include Async::App::AutoloadComponent
|
5
6
|
|
6
7
|
PATHS = ["/health", "/health/"].freeze
|
7
8
|
|
8
|
-
def
|
9
|
+
def after_init
|
9
10
|
@healthy = false
|
10
|
-
|
11
11
|
bus.subscribe("health.updated") { @healthy = _1 }
|
12
12
|
end
|
13
13
|
|
@@ -1,13 +1,16 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
class Async::App::
|
4
|
-
include Async::App::
|
3
|
+
class Async::App::WebApps::MetricsApp
|
4
|
+
include Async::App::WebComponent
|
5
|
+
include Async::App::AutoloadComponent
|
5
6
|
|
6
7
|
PATHS = ["/metrics", "/metrics/"].freeze
|
7
8
|
|
8
|
-
|
9
|
+
inject :async_app_name
|
10
|
+
|
11
|
+
def after_init
|
9
12
|
store = Store.new
|
10
|
-
@serializer = Serializer.new(prefix:
|
13
|
+
@serializer = Serializer.new(prefix: async_app_name, store:)
|
11
14
|
|
12
15
|
bus.subscribe("metrics.updated") do |metrics|
|
13
16
|
metrics.each { store.set(_1, **_2) }
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Async::App::WebComponent
|
4
|
+
def self.included(base)
|
5
|
+
base.include(Async::App::Component)
|
6
|
+
base.include(InstanceMethods)
|
7
|
+
end
|
8
|
+
|
9
|
+
module InstanceMethods
|
10
|
+
def run! = bus.publish(Async::App::WebServer::APP_ADDED, self)
|
11
|
+
|
12
|
+
def can_handle?(request) = raise NotImplementedError
|
13
|
+
def call(*) = raise NotImplementedError
|
14
|
+
end
|
15
|
+
end
|
data/lib/async/app/web_server.rb
CHANGED
@@ -1,17 +1,34 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
class Async::App::WebServer
|
4
|
-
include Async::
|
4
|
+
include Async::App::Component
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
6
|
+
APP_ADDED = "async-app.web_app.added"
|
7
|
+
|
8
|
+
class Router
|
9
|
+
def initialize
|
10
|
+
@apps = []
|
11
|
+
end
|
12
|
+
|
13
|
+
def add(app) = @apps << app
|
14
|
+
|
15
|
+
def call(request)
|
16
|
+
@apps.reverse_each { return Protocol::HTTP::Response[*_1.call(request)] if _1.can_handle?(request) }
|
17
|
+
|
18
|
+
Protocol::HTTP::Response[404, {}, ["Not found"]]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def initialize(port: 8080)
|
23
|
+
@router = Router.new
|
11
24
|
@endpoint = Async::HTTP::Endpoint.parse("http://0.0.0.0:#{port}")
|
12
25
|
end
|
13
26
|
|
14
|
-
def
|
27
|
+
def after_init = bus.subscribe(APP_ADDED) { add_app(_1) }
|
28
|
+
|
29
|
+
def add_app(app) = @router.add(app)
|
30
|
+
|
31
|
+
def run!
|
15
32
|
Async { Async::HTTP::Server.new(@router, @endpoint).run }
|
16
33
|
info { "Started on #{@endpoint.url}" }
|
17
34
|
end
|
data/lib/async/app.rb
CHANGED
@@ -1,68 +1,68 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
class Async::App
|
4
|
-
|
4
|
+
include Component
|
5
5
|
|
6
|
-
|
6
|
+
class << self
|
7
|
+
def instance = @instance = instances(self).first
|
7
8
|
|
8
|
-
|
9
|
-
|
10
|
-
# rubocop:disable Style/GlobalVars
|
11
|
-
def initialize
|
12
|
-
raise "only one instance of #{self.class} is allowed" if $__ASYNC_APP
|
9
|
+
def instances(klass) = ObjectSpace.each_object(klass)
|
10
|
+
end
|
13
11
|
|
14
|
-
|
15
|
-
|
12
|
+
def init!
|
13
|
+
raise "only one instance of #{self.class} is allowed" if instances(self.class).count > 1
|
16
14
|
|
15
|
+
@parent = Async::Task.current
|
17
16
|
set_traps!
|
18
17
|
init_container!
|
19
|
-
|
20
|
-
start_event_logger!
|
21
|
-
start_web_server!
|
22
|
-
|
23
|
-
start_runtime_metrics_collector!
|
24
|
-
|
25
|
-
run!
|
26
|
-
|
27
|
-
info { "Started" }
|
28
|
-
bus.publish("health.updated", true)
|
18
|
+
super
|
29
19
|
rescue StandardError => e
|
30
20
|
fatal { e }
|
31
|
-
stop
|
21
|
+
stop!
|
32
22
|
exit(1)
|
33
23
|
end
|
34
24
|
|
35
|
-
def
|
36
|
-
|
37
|
-
|
38
|
-
def app_name = :async_app
|
39
|
-
|
40
|
-
def stop
|
41
|
-
@task&.stop
|
42
|
-
$__ASYNC_APP = nil
|
43
|
-
info { "Stopped" }
|
25
|
+
def stop!
|
26
|
+
@parent&.stop(true)
|
27
|
+
super
|
44
28
|
end
|
45
29
|
|
46
|
-
|
30
|
+
def container = @container ||= Dry::Container.new
|
31
|
+
def instances(klass) = self.class.instances(klass)
|
32
|
+
def components = instances(Class).select { _1.included_modules.include?(Component) }.reject { _1 <= self.class }
|
33
|
+
def autoloadable_components = components.select { _1.included_modules.include?(AutoloadComponent) }
|
34
|
+
def timer_components = components.select { _1.included_modules.include?(TimerComponent) }
|
47
35
|
|
48
36
|
private
|
49
37
|
|
38
|
+
def container_config = {}
|
39
|
+
def async_app_name = :async_app
|
40
|
+
|
41
|
+
def run!
|
42
|
+
start_event_logger!
|
43
|
+
start_web_server!
|
44
|
+
|
45
|
+
autoload_components!
|
46
|
+
super
|
47
|
+
bus.publish("health.updated", true)
|
48
|
+
end
|
49
|
+
|
50
50
|
def set_traps!
|
51
51
|
trap("INT") do
|
52
52
|
force_exit! if @stopping
|
53
53
|
@stopping = true
|
54
54
|
warn { "Interrupted, stopping. Press ^C once more to force exit." }
|
55
|
-
stop
|
55
|
+
stop!
|
56
56
|
end
|
57
57
|
|
58
|
-
trap("TERM") { stop }
|
58
|
+
trap("TERM") { stop! }
|
59
59
|
end
|
60
60
|
|
61
61
|
def init_container!
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
62
|
+
container.register(:bus, Async::Bus.new)
|
63
|
+
container.register(:async_app_name, async_app_name)
|
64
|
+
|
65
|
+
container_config.each { container.register(_1, _2) }
|
66
66
|
end
|
67
67
|
|
68
68
|
def force_exit!
|
@@ -70,7 +70,7 @@ class Async::App
|
|
70
70
|
exit(1)
|
71
71
|
end
|
72
72
|
|
73
|
-
def
|
74
|
-
def
|
75
|
-
def
|
73
|
+
def autoload_components! = autoloadable_components.each { _1.new.start! }
|
74
|
+
def start_web_server! = WebServer.new.start!
|
75
|
+
def start_event_logger! = EventLogger.new.start!
|
76
76
|
end
|
data/lib/async/timer.rb
CHANGED
@@ -7,7 +7,7 @@ class Async::Timer
|
|
7
7
|
|
8
8
|
class AlreadyStarted < Error; end
|
9
9
|
|
10
|
-
def initialize(delay, # rubocop:disable Metrics/CyclomaticComplexity,Metrics/ParameterLists
|
10
|
+
def initialize(delay = nil, # rubocop:disable Metrics/CyclomaticComplexity,Metrics/ParameterLists
|
11
11
|
repeat: true,
|
12
12
|
start: true,
|
13
13
|
run_on_start: false,
|
@@ -32,14 +32,16 @@ class Async::Timer
|
|
32
32
|
|
33
33
|
def active? = @active
|
34
34
|
|
35
|
-
def restart
|
35
|
+
def restart(delay = @delay, run: false)
|
36
36
|
stop
|
37
|
-
start
|
37
|
+
start(delay, run:)
|
38
38
|
end
|
39
39
|
|
40
|
-
def start(run: false)
|
40
|
+
def start(delay = @delay, run: false)
|
41
41
|
raise AlreadyStarted, "Timer already started" if active?
|
42
|
+
raise ArgumentError, "delay cannot be nil" if delay.nil?
|
42
43
|
|
44
|
+
@delay = delay
|
43
45
|
@active = true
|
44
46
|
|
45
47
|
@task = @parent.async do
|
data/lib/async/tools/version.rb
CHANGED
data/lib/async/tools.rb
CHANGED
@@ -13,8 +13,6 @@ loader.tag = File.basename(__FILE__, ".rb")
|
|
13
13
|
loader.inflector = Zeitwerk::GemInflector.new(__FILE__)
|
14
14
|
loader.push_dir(File.expand_path("..", __dir__.to_s))
|
15
15
|
|
16
|
-
loader.setup
|
17
|
-
|
18
16
|
module Async
|
19
17
|
# Your code goes here...
|
20
18
|
module Tools # rubocop:disable Style/ClassAndModuleChildren
|
@@ -30,3 +28,6 @@ module Async
|
|
30
28
|
end
|
31
29
|
end
|
32
30
|
end
|
31
|
+
|
32
|
+
loader.setup
|
33
|
+
loader.eager_load
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
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.10
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gleb Sinyavskiy
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-03-
|
11
|
+
date: 2023-03-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: async
|
@@ -61,16 +61,19 @@ files:
|
|
61
61
|
- bin/console
|
62
62
|
- bin/setup
|
63
63
|
- lib/async/app.rb
|
64
|
+
- lib/async/app/autoload_component.rb
|
64
65
|
- lib/async/app/component.rb
|
65
66
|
- lib/async/app/event_logger.rb
|
66
67
|
- lib/async/app/injector.rb
|
68
|
+
- lib/async/app/metrics/components_metrics_collector.rb
|
67
69
|
- lib/async/app/metrics/ruby_runtime_metrics_collector.rb
|
70
|
+
- lib/async/app/timer_component.rb
|
71
|
+
- lib/async/app/web_apps/health_app.rb
|
72
|
+
- lib/async/app/web_apps/metrics_app.rb
|
73
|
+
- lib/async/app/web_apps/metrics_app/serializer.rb
|
74
|
+
- lib/async/app/web_apps/metrics_app/store.rb
|
75
|
+
- lib/async/app/web_component.rb
|
68
76
|
- lib/async/app/web_server.rb
|
69
|
-
- lib/async/app/web_server/health_app.rb
|
70
|
-
- lib/async/app/web_server/metrics_app.rb
|
71
|
-
- lib/async/app/web_server/metrics_app/serializer.rb
|
72
|
-
- lib/async/app/web_server/metrics_app/store.rb
|
73
|
-
- lib/async/app/web_server/router.rb
|
74
77
|
- lib/async/bus.rb
|
75
78
|
- lib/async/cache.rb
|
76
79
|
- lib/async/channel.rb
|
@@ -1,15 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
class Async::App::WebServer::Router
|
4
|
-
extend Async::App::Injector
|
5
|
-
|
6
|
-
def initialize(*apps)
|
7
|
-
@apps = apps
|
8
|
-
end
|
9
|
-
|
10
|
-
def call(request)
|
11
|
-
@apps.each { return Protocol::HTTP::Response[*_1.call(request)] if _1.can_handle?(request) }
|
12
|
-
|
13
|
-
Protocol::HTTP::Response[404, {}, ["Not found"]]
|
14
|
-
end
|
15
|
-
end
|