async-container-supervisor 0.4.1 → 0.5.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bb05adfa242cb60f47bd8dbe08da5e8c7d0250c450c7e9eee8b08b8a61f1670d
4
- data.tar.gz: 0ffabcd3c5423f52c0912dc68af62b6cd2a7d1de0c74ff6fd5cc1175413f100e
3
+ metadata.gz: 6a910d75fb13f17155f9786202f2ca613ca581cd2aa171c942638dc22a372aa9
4
+ data.tar.gz: 51b89119b6d9a77511a19436a09f21796bc0a88c0f1d9e0542cf530e18034242
5
5
  SHA512:
6
- metadata.gz: b3b3aba809104243badeeb0a18a9bccea0b6e49e34f1ce71b2f35c0d4f1f41718287858e6d400a869dd7ea4db9378448184084d81f4dec8363cdcc9cafce07d2
7
- data.tar.gz: 2719f1d43025b031b577289460272d7c340ca297cf49b4325e2e095e361db926fba7a85cf6b80ff6c973f5ee464b69545c1c4d43a45f48b517c8801eb46a3c54
6
+ metadata.gz: 8e80d6ba0aa70e17aa8ec115d3536c4f38654e8403bd8a74a8bbc80014116035adeb68887a53d4e9eb13f03ec20dc286a8e24386bab1745ef6e0237baa0347bb
7
+ data.tar.gz: 97e1560def4b68e8a0afe42f6a7c6bdda005903ffb11edd909b9ec8c9756daed13d8e38f11c0ed0042b34202665216a0a39f948a51a2bbf348fd8933e33a3eef
checksums.yaml.gz.sig CHANGED
Binary file
@@ -56,8 +56,11 @@ module Async
56
56
  end
57
57
 
58
58
  def finish(**response)
59
- self.push(id: @id, finished: true, **response)
60
- @queue.close
59
+ # If the remote end has already closed the connection, we don't need to send a finished message:
60
+ unless @queue.closed?
61
+ self.push(id: @id, finished: true, **response)
62
+ @queue.close
63
+ end
61
64
  end
62
65
 
63
66
  def fail(**response)
@@ -10,25 +10,44 @@ module Async
10
10
  module Container
11
11
  module Supervisor
12
12
  class MemoryMonitor
13
- def initialize(interval: 10, limit: nil, &block)
13
+ # Create a new memory monitor.
14
+ #
15
+ # @parameter interval [Integer] The interval at which to check for memory leaks.
16
+ # @parameter total_size_limit [Integer] The total size limit of all processes, or nil for no limit.
17
+ # @parameter options [Hash] Options to pass to the cluster when adding processes.
18
+ def initialize(interval: 10, total_size_limit: nil, **options)
14
19
  @interval = interval
15
- @cluster = Memory::Leak::Cluster.new(limit: limit)
20
+ @cluster = Memory::Leak::Cluster.new(total_size_limit: total_size_limit)
21
+
22
+ # We use these options when adding processes to the cluster:
23
+ @options = options
24
+
16
25
  @processes = Hash.new{|hash, key| hash[key] = Set.new.compare_by_identity}
17
26
  end
18
27
 
28
+ # Add a process to the memory monitor. You may override this to control how processes are added to the cluster.
29
+ #
30
+ # @parameter process_id [Integer] The process ID to add.
31
+ def add(process_id)
32
+ @cluster.add(process_id, **@options)
33
+ end
34
+
35
+ # Register the connection (worker) with the memory monitor.
19
36
  def register(connection)
37
+ Console.debug(self, "Registering connection:", connection: connection, state: connection.state)
20
38
  if process_id = connection.state[:process_id]
21
39
  connections = @processes[process_id]
22
40
 
23
41
  if connections.empty?
24
- Console.info(self, "Registering process:", process_id: process_id)
25
- @cluster.add(process_id)
42
+ Console.debug(self, "Registering process:", process_id: process_id)
43
+ self.add(process_id)
26
44
  end
27
45
 
28
46
  connections.add(connection)
29
47
  end
30
48
  end
31
49
 
50
+ # Remove the connection (worker) from the memory monitor.
32
51
  def remove(connection)
33
52
  if process_id = connection.state[:process_id]
34
53
  connections = @processes[process_id]
@@ -36,34 +55,41 @@ module Async
36
55
  connections.delete(connection)
37
56
 
38
57
  if connections.empty?
39
- Console.info(self, "Removing process:", process_id: process_id)
58
+ Console.debug(self, "Removing process:", process_id: process_id)
40
59
  @cluster.remove(process_id)
41
60
  end
42
61
  end
43
62
  end
44
63
 
64
+ # Dump the current status of the memory monitor.
65
+ #
66
+ # @parameter call [Connection::Call] The call to respond to.
45
67
  def status(call)
46
68
  call.push(memory_monitor: @cluster)
47
69
  end
48
70
 
71
+ # Invoked when a memory leak is detected.
72
+ #
73
+ # @parameter process_id [Integer] The process ID of the process that has a memory leak.
74
+ # @parameter monitor [Memory::Leak::Monitor] The monitor that detected the memory leak.
75
+ # @returns [Boolean] True if the process was killed.
76
+ def memory_leak_detected(process_id, monitor)
77
+ Console.info(self, "Killing process:", process_id: process_id)
78
+ Process.kill(:INT, process_id)
79
+
80
+ true
81
+ end
82
+
83
+ # Run the memory monitor.
84
+ #
85
+ # @returns [Async::Task] The task that is running the memory monitor.
49
86
  def run
50
87
  Async do
51
88
  while true
89
+ # This block must return true if the process was killed.
52
90
  @cluster.check! do |process_id, monitor|
53
91
  Console.error(self, "Memory leak detected in process:", process_id: process_id, monitor: monitor)
54
- connections = @processes[process_id]
55
-
56
- connections.each do |connection|
57
- path = "/tmp/memory_dump_#{process_id}.json"
58
-
59
- response = connection.call(do: :memory_dump, path: path, timeout: 30)
60
- Console.info(self, "Memory dump saved to:", path, response: response)
61
- @block.call(response) if @block
62
- end
63
-
64
- # Kill the process:
65
- Console.info(self, "Killing process:", process_id: process_id)
66
- Process.kill(:INT, process_id)
92
+ memory_leak_detected(process_id, monitor)
67
93
  end
68
94
 
69
95
  sleep(@interval)
@@ -6,7 +6,7 @@
6
6
  module Async
7
7
  module Container
8
8
  module Supervisor
9
- VERSION = "0.4.1"
9
+ VERSION = "0.5.1"
10
10
  end
11
11
  end
12
12
  end
@@ -13,3 +13,13 @@ require_relative "supervisor/memory_monitor"
13
13
 
14
14
  require_relative "supervisor/environment"
15
15
  require_relative "supervisor/supervised"
16
+
17
+ # @namespace
18
+ module Async
19
+ # @namespace
20
+ module Container
21
+ # @namespace
22
+ module Supervisor
23
+ end
24
+ end
25
+ end
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: async-container-supervisor
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.1
4
+ version: 0.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
@@ -36,7 +36,7 @@ cert_chain:
36
36
  Q2K9NVun/S785AP05vKkXZEFYxqG6EW012U4oLcFl5MySFajYXRYbuUpH6AY+HP8
37
37
  voD0MPg1DssDLKwXyt1eKD/+Fq0bFWhwVM/1XiAXL7lyYUyOq24KHgQ2Csg=
38
38
  -----END CERTIFICATE-----
39
- date: 2025-02-27 00:00:00.000000000 Z
39
+ date: 2025-02-28 00:00:00.000000000 Z
40
40
  dependencies:
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: async-container
@@ -86,14 +86,14 @@ dependencies:
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '0.3'
89
+ version: '0.5'
90
90
  type: :runtime
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: '0.3'
96
+ version: '0.5'
97
97
  executables: []
98
98
  extensions: []
99
99
  extra_rdoc_files: []
metadata.gz.sig CHANGED
Binary file