async-container-supervisor 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: ecde9321579fc86b6e3af0434fe518fefa5c63e161a68e8b982fa74028b5db43
4
+ data.tar.gz: 754cf3efc6d28f4f4e8e97da1ddfbad020a23578bbc710a81d4a7cc302d89912
5
+ SHA512:
6
+ metadata.gz: c0105355ee822e38cf60d3adf43192ab070766efbf5b54ef87283ac4cf7e0a7ed211f4154045ce91e2f9566cfe4478e1a51799fc04a40e1504c1749dd0420802
7
+ data.tar.gz: 21ffe53df327d2d8ba1b669316473bf571bbdae79dac7f1c50bb88c5198c72be9025b6620218ccac7e1a9bba0a19bb457182873d3b5a56399f8c09977d4707e5
checksums.yaml.gz.sig ADDED
Binary file
@@ -0,0 +1,125 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2025, by Samuel Williams.
5
+
6
+ require "io/stream"
7
+ require_relative "connection"
8
+
9
+ module Async
10
+ module Container
11
+ module Supervisor
12
+ class Client
13
+ def self.run(...)
14
+ self.new(...).run
15
+ end
16
+
17
+ def initialize(instance, endpoint = Supervisor.endpoint)
18
+ @instance = instance
19
+ @endpoint = endpoint
20
+ end
21
+
22
+ def dispatch(call)
23
+ method_name = "do_#{call.message[:do]}"
24
+ self.public_send(method_name, call)
25
+ end
26
+
27
+ def connect
28
+ unless @connection
29
+ peer = @endpoint.connect
30
+ stream = IO::Stream(peer)
31
+ @connection = Connection.new(stream, 0, instance: @instance)
32
+
33
+ # Register the instance with the server:
34
+ Async do
35
+ @connection.call(do: :register, state: @instance)
36
+ end
37
+ end
38
+
39
+ return @connection unless block_given?
40
+
41
+ begin
42
+ yield @connection
43
+ ensure
44
+ @connection.close
45
+ end
46
+ end
47
+
48
+ def close
49
+ if connection = @connection
50
+ @connection = nil
51
+ connection.close
52
+ end
53
+ end
54
+
55
+ private def dump(call)
56
+ if path = call[:path]
57
+ File.open(path, "w") do |file|
58
+ yield file
59
+ end
60
+
61
+ call.finish(path: path)
62
+ else
63
+ buffer = StringIO.new
64
+ yield buffer
65
+
66
+ call.finish(data: buffer.string)
67
+ end
68
+ end
69
+
70
+ def do_scheduler_dump(call)
71
+ dump(call) do |file|
72
+ Fiber.scheduler.print_hierarchy(file)
73
+ end
74
+ end
75
+
76
+ def do_memory_dump(call)
77
+ require "objspace"
78
+
79
+ dump(call) do |file|
80
+ ObjectSpace.dump_all(output: file)
81
+ end
82
+ end
83
+
84
+ def do_thread_dump(call)
85
+ dump(call) do |file|
86
+ Thread.list.each do |thread|
87
+ file.puts(thread.inspect)
88
+ file.puts(thread.backtrace)
89
+ end
90
+ end
91
+ end
92
+
93
+ def do_garbage_profile_start(call)
94
+ GC::Profiler.enable
95
+ call.finish(started: true)
96
+ end
97
+
98
+ def do_garbage_profile_stop(call)
99
+ GC::Profiler.disable
100
+
101
+ dump(connection, message) do |file|
102
+ file.puts GC::Profiler.result
103
+ end
104
+ end
105
+
106
+ def run
107
+ Async do |task|
108
+ loop do
109
+ connect do |connection|
110
+ connection.run(self)
111
+ end
112
+ rescue => error
113
+ Console.error(self, "Unexpected error while running client!", exception: error)
114
+
115
+ # Retry after a small delay:
116
+ sleep(rand)
117
+ end
118
+ ensure
119
+ task.stop
120
+ end
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,165 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2025, by Samuel Williams.
5
+
6
+ require "json"
7
+
8
+ module Async
9
+ module Container
10
+ module Supervisor
11
+ class Connection
12
+ class Call
13
+ def initialize(connection, id, message)
14
+ @connection = connection
15
+ @id = id
16
+ @message = message
17
+
18
+ @queue = ::Thread::Queue.new
19
+ end
20
+
21
+ # @attribute [Connection] The connection that initiated the call.
22
+ attr :connection
23
+
24
+ # @attribute [Hash] The message that initiated the call.
25
+ attr :message
26
+
27
+ def [] key
28
+ @message[key]
29
+ end
30
+
31
+ def push(**response)
32
+ @queue.push(response)
33
+ end
34
+
35
+ def pop(...)
36
+ @queue.pop(...)
37
+ end
38
+
39
+ def each(&block)
40
+ while response = self.pop
41
+ yield response
42
+ end
43
+ end
44
+
45
+ def finish(**response)
46
+ self.push(id: @id, finished: true, **response)
47
+ @queue.close
48
+ end
49
+
50
+ def closed?
51
+ @queue.closed?
52
+ end
53
+
54
+ def self.dispatch(connection, target, id, message)
55
+ Async do
56
+ call = self.new(connection, id, message)
57
+ connection.calls[id] = call
58
+
59
+ target.dispatch(call)
60
+
61
+ while response = call.pop
62
+ connection.write(id: id, **response)
63
+ end
64
+ ensure
65
+ # If the queue is closed, we don't need to send a finished message.
66
+ unless call.closed?
67
+ connection.write(id: id, finished: true)
68
+ end
69
+
70
+ connection.calls.delete(id)
71
+ end
72
+ end
73
+
74
+ def self.call(connection, **message, &block)
75
+ id = connection.next_id
76
+ call = self.new(connection, id, message)
77
+
78
+ connection.calls[id] = call
79
+ connection.write(id: id, **message)
80
+
81
+ if block_given?
82
+ call.each(&block)
83
+ else
84
+ return call.pop
85
+ end
86
+ end
87
+ end
88
+
89
+ def initialize(stream, id, **state)
90
+ @stream = stream
91
+ @state = state
92
+
93
+ @calls = {}
94
+
95
+ @id = id
96
+ end
97
+
98
+ # @attribute [Hash(Integer, Call)] Calls in progress.
99
+ attr :calls
100
+
101
+ # @attribute [Hash(Symbol, Object)] State associated with this connection, for example the process ID, etc.
102
+ attr_accessor :state
103
+
104
+ def next_id
105
+ @id += 2
106
+ end
107
+
108
+ def write(**message)
109
+ @stream.write(JSON.dump(message) << "\n")
110
+ @stream.flush
111
+ end
112
+
113
+ def call(timeout: nil, **message)
114
+ id = next_id
115
+ calls[id] = ::Thread::Queue.new
116
+
117
+ write(id: id, **message)
118
+
119
+ return calls[id].pop(timeout: timeout)
120
+ ensure
121
+ calls.delete(id)
122
+ end
123
+
124
+ def read
125
+ if line = @stream&.gets
126
+ JSON.parse(line, symbolize_names: true)
127
+ end
128
+ end
129
+
130
+ def each
131
+ while message = self.read
132
+ yield message
133
+ end
134
+ end
135
+
136
+ def call(...)
137
+ Call.call(self, ...)
138
+ end
139
+
140
+ def run(target)
141
+ self.each do |message|
142
+ if id = message[:id]
143
+ if call = @calls[id]
144
+ # Response to a call:
145
+ call.push(**message)
146
+ else
147
+ # Incoming call:
148
+ Call.dispatch(self, target, id, message)
149
+ end
150
+ else
151
+ Console.error(self, "Unknown message:", message)
152
+ end
153
+ end
154
+ end
155
+
156
+ def close
157
+ if stream = @stream
158
+ @stream = nil
159
+ stream.close
160
+ end
161
+ end
162
+ end
163
+ end
164
+ end
165
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2025, by Samuel Williams.
5
+
6
+ require "io/endpoint/unix_endpoint"
7
+
8
+ module Async
9
+ module Container
10
+ module Supervisor
11
+ def self.endpoint(path = "supervisor.ipc")
12
+ ::IO::Endpoint.unix(path)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2025, by Samuel Williams.
5
+
6
+ require "async/service/environment"
7
+
8
+ module Async
9
+ module Container
10
+ module Supervisor
11
+ module Environment
12
+ # The service class to use for the supervisor.
13
+ # @returns [Class]
14
+ def service_class
15
+ Supervisor::Service
16
+ end
17
+
18
+ # The name of the supervisor
19
+ # @returns [String]
20
+ def name
21
+ "supervisor"
22
+ end
23
+
24
+ # The IPC path to use for communication with the supervisor.
25
+ # @returns [String]
26
+ def ipc_path
27
+ ::File.expand_path("supervisor.ipc", root)
28
+ end
29
+
30
+ # The endpoint the supervisor will bind to.
31
+ # @returns [::IO::Endpoint::Generic]
32
+ def endpoint
33
+ ::IO::Endpoint.unix(ipc_path)
34
+ end
35
+
36
+ # Options to use when creating the container.
37
+ def container_options
38
+ {restart: true, count: 1, health_check_timeout: 30}
39
+ end
40
+
41
+ def monitors
42
+ []
43
+ end
44
+
45
+ def make_server(endpoint)
46
+ Server.new(endpoint, monitors: self.monitors)
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2025, by Samuel Williams.
5
+
6
+ require "memory/leak/cluster"
7
+ require "set"
8
+
9
+ module Async
10
+ module Container
11
+ module Supervisor
12
+ class MemoryMonitor
13
+ def initialize(interval: 10, limit: nil)
14
+ @interval = interval
15
+ @cluster = Memory::Leak::Cluster.new(limit: limit)
16
+ @processes = Hash.new{|hash, key| hash[key] = Set.new.compare_by_identity}
17
+ end
18
+
19
+ def register(connection)
20
+ if process_id = connection.state[:process_id]
21
+ connections = @processes[process_id]
22
+
23
+ if connections.empty?
24
+ Console.info(self, "Registering process:", process_id: process_id)
25
+ @cluster.add(process_id)
26
+ end
27
+
28
+ connections.add(connection)
29
+ end
30
+ end
31
+
32
+ def remove(connection)
33
+ if process_id = connection.state[:process_id]
34
+ connections = @processes[process_id]
35
+
36
+ connections.delete(connection)
37
+
38
+ if connections.empty?
39
+ Console.info(self, "Removing process:", process_id: process_id)
40
+ @cluster.remove(process_id)
41
+ end
42
+ end
43
+ end
44
+
45
+ def run
46
+ Async do
47
+ while true
48
+ @cluster.check! do |process_id, monitor|
49
+ Console.error(self, "Memory leak detected in process:", process_id: process_id, monitor: monitor)
50
+ connections = @processes[process_id]
51
+
52
+ connections.each do |connection|
53
+ path = "/tmp/memory_dump_#{process_id}.json"
54
+
55
+ response = connection.call(do: :memory_dump, path: path, timeout: 30)
56
+ Console.info(self, "Memory dump saved to:", path, response: response)
57
+ end
58
+
59
+ # Kill the process:
60
+ Console.info(self, "Killing process:", process_id: process_id)
61
+ Process.kill(:INT, process_id)
62
+ end
63
+
64
+ sleep(@interval)
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2025, by Samuel Williams.
5
+
6
+ require_relative "connection"
7
+ require_relative "endpoint"
8
+
9
+ require "io/stream"
10
+
11
+ module Async
12
+ module Container
13
+ module Supervisor
14
+ class Server
15
+ def initialize(endpoint = Supervisor.endpoint, monitors: [])
16
+ @endpoint = endpoint
17
+ @monitors = monitors
18
+ end
19
+
20
+ attr :monitors
21
+
22
+ def dispatch(call)
23
+ method_name = "do_#{call.message[:do]}"
24
+ self.public_send(method_name, call)
25
+ end
26
+
27
+ def do_register(call)
28
+ call.connection.state.merge!(call.message[:state])
29
+
30
+ @monitors.each do |monitor|
31
+ begin
32
+ monitor.register(call.connection)
33
+ rescue => error
34
+ Console.error(self, "Error while registering process!", monitor: monitor, exception: error)
35
+ end
36
+ end
37
+ ensure
38
+ call.finish
39
+ end
40
+
41
+ def remove(connection)
42
+ @monitors.each do |monitor|
43
+ begin
44
+ monitor.remove(connection)
45
+ rescue => error
46
+ Console.error(self, "Error while removing process!", monitor: monitor, exception: error)
47
+ end
48
+ end
49
+ end
50
+
51
+ def run
52
+ Async do |task|
53
+ @monitors.each do |monitor|
54
+ begin
55
+ monitor.run
56
+ rescue => error
57
+ Console.error(self, "Error while starting monitor!", monitor: monitor, exception: error)
58
+ end
59
+ end
60
+
61
+ @endpoint.accept do |peer|
62
+ stream = IO::Stream(peer)
63
+ connection = Connection.new(stream, 1, remote_address: peer.remote_address)
64
+ connection.run(self)
65
+ ensure
66
+ connection.close
67
+ remove(connection)
68
+ end
69
+
70
+ task.children&.each(&:wait)
71
+ ensure
72
+ task.stop
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2025, by Samuel Williams.
5
+
6
+ require "async"
7
+ require "async/service/generic"
8
+ require "io/endpoint/bound_endpoint"
9
+
10
+ module Async
11
+ module Container
12
+ module Supervisor
13
+ class Service < Async::Service::Generic
14
+ # Initialize the supervisor using the given environment.
15
+ # @parameter environment [Build::Environment]
16
+ def initialize(...)
17
+ super
18
+
19
+ @bound_endpoint = nil
20
+ end
21
+
22
+ # The endpoint which the supervisor will bind to.
23
+ # Typically a unix pipe in the same directory as the host.
24
+ def endpoint
25
+ @evaluator.endpoint
26
+ end
27
+
28
+ # Bind the supervisor to the specified endpoint.
29
+ def start
30
+ @bound_endpoint = self.endpoint.bound
31
+
32
+ super
33
+ end
34
+
35
+ def name
36
+ @evaluator.name
37
+ end
38
+
39
+ def setup(container)
40
+ container_options = @evaluator.container_options
41
+ health_check_timeout = container_options[:health_check_timeout]
42
+
43
+ container.run(name: self.name, **container_options) do |instance|
44
+ evaluator = @environment.evaluator
45
+
46
+ Async do
47
+ server = evaluator.make_server(@bound_endpoint)
48
+ server.run
49
+
50
+ instance.ready!
51
+
52
+ if health_check_timeout
53
+ Async(transient: true) do
54
+ while true
55
+ sleep(health_check_timeout / 2)
56
+ instance.ready!
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
62
+
63
+ super
64
+ end
65
+
66
+ # Release the bound endpoint.
67
+ def stop
68
+ @bound_endpoint&.close
69
+ @bound_endpoint = nil
70
+
71
+ super
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2025, by Samuel Williams.
5
+
6
+ module Async
7
+ module Container
8
+ module Supervisor
9
+ VERSION = "0.1.0"
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2025, by Samuel Williams.
5
+
6
+ require_relative "supervisor/version"
7
+
8
+ require_relative "supervisor/server"
9
+ require_relative "supervisor/client"
10
+
11
+ require_relative "supervisor/memory_monitor"
12
+
13
+ require_relative "supervisor/environment"
14
+ require_relative "supervisor/service"
data/license.md ADDED
@@ -0,0 +1,21 @@
1
+ # MIT License
2
+
3
+ Copyright, 2025, by Samuel Williams.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/readme.md ADDED
@@ -0,0 +1,43 @@
1
+ # Async::Container::Supervisor
2
+
3
+ Provides a supervisor service for
4
+
5
+ [![Development Status](https://github.com/socketry/async-container-supervisor/workflows/Test/badge.svg)](https://github.com/socketry/async-container-supervisor/actions?workflow=Test)
6
+
7
+ ## Features
8
+
9
+ - Supports multi-process, multi-thread and hybrid containers.
10
+ - Automatic scalability based on physical hardware.
11
+ - Direct integration with [systemd](https://www.freedesktop.org/software/systemd/man/sd_notify.html) using `$NOTIFY_SOCKET`.
12
+ - Internal process readiness protocol for handling state changes.
13
+ - Automatic restart of failed processes.
14
+
15
+ ## Usage
16
+
17
+ Please see the [project documentation](https://socketry.github.io/async-container-supervisor/) for more details.
18
+
19
+ ## Releases
20
+
21
+ Please see the [project releases](https://socketry.github.io/async-container-supervisor/releases/index) for all releases.
22
+
23
+ ### v0.1.0
24
+
25
+ - Initial implementation.
26
+
27
+ ## Contributing
28
+
29
+ We welcome contributions to this project.
30
+
31
+ 1. Fork it.
32
+ 2. Create your feature branch (`git checkout -b my-new-feature`).
33
+ 3. Commit your changes (`git commit -am 'Add some feature'`).
34
+ 4. Push to the branch (`git push origin my-new-feature`).
35
+ 5. Create new Pull Request.
36
+
37
+ ### Developer Certificate of Origin
38
+
39
+ In order to protect users of this project, we require all contributors to comply with the [Developer Certificate of Origin](https://developercertificate.org/). This ensures that all contributions are properly licensed and attributed.
40
+
41
+ ### Community Guidelines
42
+
43
+ This project is best served by a collaborative and respectful environment. Treat each other professionally, respect differing viewpoints, and engage constructively. Harassment, discrimination, or harmful behavior is not tolerated. Communicate clearly, listen actively, and support one another. If any issues arise, please inform the project maintainers.
data/releases.md ADDED
@@ -0,0 +1,5 @@
1
+ # Releases
2
+
3
+ ## v0.1.0
4
+
5
+ - Initial implementation.
data.tar.gz.sig ADDED
Binary file
metadata ADDED
@@ -0,0 +1,150 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: async-container-supervisor
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Samuel Williams
8
+ bindir: bin
9
+ cert_chain:
10
+ - |
11
+ -----BEGIN CERTIFICATE-----
12
+ MIIE2DCCA0CgAwIBAgIBATANBgkqhkiG9w0BAQsFADBhMRgwFgYDVQQDDA9zYW11
13
+ ZWwud2lsbGlhbXMxHTAbBgoJkiaJk/IsZAEZFg1vcmlvbnRyYW5zZmVyMRIwEAYK
14
+ CZImiZPyLGQBGRYCY28xEjAQBgoJkiaJk/IsZAEZFgJuejAeFw0yMjA4MDYwNDUz
15
+ MjRaFw0zMjA4MDMwNDUzMjRaMGExGDAWBgNVBAMMD3NhbXVlbC53aWxsaWFtczEd
16
+ MBsGCgmSJomT8ixkARkWDW9yaW9udHJhbnNmZXIxEjAQBgoJkiaJk/IsZAEZFgJj
17
+ bzESMBAGCgmSJomT8ixkARkWAm56MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIB
18
+ igKCAYEAomvSopQXQ24+9DBB6I6jxRI2auu3VVb4nOjmmHq7XWM4u3HL+pni63X2
19
+ 9qZdoq9xt7H+RPbwL28LDpDNflYQXoOhoVhQ37Pjn9YDjl8/4/9xa9+NUpl9XDIW
20
+ sGkaOY0eqsQm1pEWkHJr3zn/fxoKPZPfaJOglovdxf7dgsHz67Xgd/ka+Wo1YqoE
21
+ e5AUKRwUuvaUaumAKgPH+4E4oiLXI4T1Ff5Q7xxv6yXvHuYtlMHhYfgNn8iiW8WN
22
+ XibYXPNP7NtieSQqwR/xM6IRSoyXKuS+ZNGDPUUGk8RoiV/xvVN4LrVm9upSc0ss
23
+ RZ6qwOQmXCo/lLcDUxJAgG95cPw//sI00tZan75VgsGzSWAOdjQpFM0l4dxvKwHn
24
+ tUeT3ZsAgt0JnGqNm2Bkz81kG4A2hSyFZTFA8vZGhp+hz+8Q573tAR89y9YJBdYM
25
+ zp0FM4zwMNEUwgfRzv1tEVVUEXmoFCyhzonUUw4nE4CFu/sE3ffhjKcXcY//qiSW
26
+ xm4erY3XAgMBAAGjgZowgZcwCQYDVR0TBAIwADALBgNVHQ8EBAMCBLAwHQYDVR0O
27
+ BBYEFO9t7XWuFf2SKLmuijgqR4sGDlRsMC4GA1UdEQQnMCWBI3NhbXVlbC53aWxs
28
+ aWFtc0BvcmlvbnRyYW5zZmVyLmNvLm56MC4GA1UdEgQnMCWBI3NhbXVlbC53aWxs
29
+ aWFtc0BvcmlvbnRyYW5zZmVyLmNvLm56MA0GCSqGSIb3DQEBCwUAA4IBgQB5sxkE
30
+ cBsSYwK6fYpM+hA5B5yZY2+L0Z+27jF1pWGgbhPH8/FjjBLVn+VFok3CDpRqwXCl
31
+ xCO40JEkKdznNy2avOMra6PFiQyOE74kCtv7P+Fdc+FhgqI5lMon6tt9rNeXmnW/
32
+ c1NaMRdxy999hmRGzUSFjozcCwxpy/LwabxtdXwXgSay4mQ32EDjqR1TixS1+smp
33
+ 8C/NCWgpIfzpHGJsjvmH2wAfKtTTqB9CVKLCWEnCHyCaRVuKkrKjqhYCdmMBqCws
34
+ JkxfQWC+jBVeG9ZtPhQgZpfhvh+6hMhraUYRQ6XGyvBqEUe+yo6DKIT3MtGE2+CP
35
+ eX9i9ZWBydWb8/rvmwmX2kkcBbX0hZS1rcR593hGc61JR6lvkGYQ2MYskBveyaxt
36
+ Q2K9NVun/S785AP05vKkXZEFYxqG6EW012U4oLcFl5MySFajYXRYbuUpH6AY+HP8
37
+ voD0MPg1DssDLKwXyt1eKD/+Fq0bFWhwVM/1XiAXL7lyYUyOq24KHgQ2Csg=
38
+ -----END CERTIFICATE-----
39
+ date: 2025-02-26 00:00:00.000000000 Z
40
+ dependencies:
41
+ - !ruby/object:Gem::Dependency
42
+ name: async-container
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0.22'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '0.22'
55
+ - !ruby/object:Gem::Dependency
56
+ name: async-service
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: io-endpoint
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: io-stream
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: memory-leak
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '0.3'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '0.3'
111
+ executables: []
112
+ extensions: []
113
+ extra_rdoc_files: []
114
+ files:
115
+ - lib/async/container/supervisor.rb
116
+ - lib/async/container/supervisor/client.rb
117
+ - lib/async/container/supervisor/connection.rb
118
+ - lib/async/container/supervisor/endpoint.rb
119
+ - lib/async/container/supervisor/environment.rb
120
+ - lib/async/container/supervisor/memory_monitor.rb
121
+ - lib/async/container/supervisor/server.rb
122
+ - lib/async/container/supervisor/service.rb
123
+ - lib/async/container/supervisor/version.rb
124
+ - license.md
125
+ - readme.md
126
+ - releases.md
127
+ homepage: https://github.com/socketry/async-container-supervisor
128
+ licenses:
129
+ - MIT
130
+ metadata:
131
+ documentation_uri: https://socketry.github.io/async-container-supervisor/
132
+ source_code_uri: https://github.com/socketry/async-container-supervisor.git
133
+ rdoc_options: []
134
+ require_paths:
135
+ - lib
136
+ required_ruby_version: !ruby/object:Gem::Requirement
137
+ requirements:
138
+ - - ">="
139
+ - !ruby/object:Gem::Version
140
+ version: '3.1'
141
+ required_rubygems_version: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ requirements: []
147
+ rubygems_version: 3.6.2
148
+ specification_version: 4
149
+ summary: A supervisor for managing multiple container processes.
150
+ test_files: []
metadata.gz.sig ADDED
Binary file