main_loop 0.1.3.16874 → 0.1.4.364822

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: 9ddfd174c8f04a96a34dbddcfe2a4ee59e5747e52ffcd0403d3444c1d0d24356
4
- data.tar.gz: 5a0ead0ebbc98c8f494eeb5166086e8aeed51c7b276d2deb6bffb2f16d300ebf
3
+ metadata.gz: ec4bfd3358113dae75080b98525dcec837de50f484b9df20b6d19b0b93cfae12
4
+ data.tar.gz: 65e3173cd2c269a8c6ed8a1d2ca0a3ca9a94a7903c363901f3d82fe834f8e160
5
5
  SHA512:
6
- metadata.gz: 18d1ef3fb48243f552efd0b703687f4b071cf05b2216f33b194aa80f5d343b80ee1035d25193fadbb0cc8582f70508793022a095166f952756f9b493d108b315
7
- data.tar.gz: ad9e2b8cf3d045550bbfd9b08f8e0997194211a17a7d450d7c00256c604944172c9a6f98efdfedb0323cc81a51109ddf5e27bd3b12d214734b95c7d6351f1b93
6
+ metadata.gz: a82577aaf2f8c3620a7bf45dd2baa08f1ec3e5da6d2ea9cc280ac7c7b78f974bfd0c5ae85eba516c4fec7d35fa7cb46207efbc9679b85b53d30f1bb5f555cdbc
7
+ data.tar.gz: 6c31a0c1f9e9c8294f45e3f15839379533ee5a7a2b40c021c25ff977977133ac1e77a6262d25148039fa675c313d6e403927f7259f33780e75fac6e7f5e667d6
data/README.md CHANGED
@@ -4,11 +4,10 @@
4
4
  [![Gem](https://img.shields.io/gem/dt/main_loop.svg)](https://rubygems.org/gems/main_loop/versions)
5
5
  [![YARD](https://badgen.net/badge/YARD/doc/blue)](http://www.rubydoc.info/gems/main_loop)
6
6
 
7
- [![Test Coverage](https://api.codeclimate.com/v1/badges/baf9b1dc3dae87f7edfd/test_coverage)](https://codeclimate.com/github/RnD-Soft/main_loop/test_coverage)
8
- [![Maintainability](https://api.codeclimate.com/v1/badges/baf9b1dc3dae87f7edfd/maintainability)](https://codeclimate.com/github/RnD-Soft/main_loop/maintainability)
9
- [![Quality](https://lysander.x.rnds.pro/api/v1/badges/main_loop_quality.svg)](https://lysander.x.rnds.pro/api/v1/badges/main_loop_quality.html)
10
- [![Outdated](https://lysander.x.rnds.pro/api/v1/badges/main_loop_outdated.svg)](https://lysander.x.rnds.pro/api/v1/badges/main_loop_outdated.html)
11
- [![Vulnerabilities](https://lysander.x.rnds.pro/api/v1/badges/main_loop_vulnerable.svg)](https://lysander.x.rnds.pro/api/v1/badges/main_loop_vulnerable.html)
7
+ [![Coverage](https://lysander.rnds.pro/api/v1/badges/main_loop_coverage.svg)](https://lysander.rnds.pro/api/v1/badges/main_loop_coverage.html)
8
+ [![Quality](https://lysander.rnds.pro/api/v1/badges/main_loop_quality.svg)](https://lysander.rnds.pro/api/v1/badges/main_loop_quality.html)
9
+ [![Outdated](https://lysander.rnds.pro/api/v1/badges/main_loop_outdated.svg)](https://lysander.rnds.pro/api/v1/badges/main_loop_outdated.html)
10
+ [![Vulnerabilities](https://lysander.rnds.pro/api/v1/badges/main_loop_vulnerable.svg)](https://lysander.rnds.pro/api/v1/badges/main_loop_vulnerable.html)
12
11
 
13
12
  MainLoop is a simple main application implementation to control subprocesses(children) and threads.
14
13
 
@@ -26,10 +26,10 @@ module MainLoop
26
26
  def reap_by_id(id, status)
27
27
  synchronize do
28
28
  if (handler = handlers.find {|h| h.id == id })
29
- logger.info("Reap handler #{handler.name.inspect}. Status: #{status.inspect}")
29
+ logger.info("Reap handler #{handler.name.inspect}. Status: #{status&.inspect}")
30
30
  handler.reap(status)
31
31
  else
32
- logger.debug("Reap unknown handler. Status: #{status.inspect}. Skipped")
32
+ logger.debug("Reap unknown handler. Status: #{status&.inspect}. Skipped")
33
33
  end
34
34
  end
35
35
  end
@@ -81,10 +81,10 @@ module MainLoop
81
81
  def handle_retry
82
82
  if @retry_count == :unlimited
83
83
  logger.info "#{@handler_type}[#{name}] retry...."
84
- self.run(&@block)
84
+ self.run
85
85
  elsif @retry_count && (@retry_count -= 1) >= 0
86
86
  logger.info "#{@handler_type}[#{name}] retry...."
87
- self.run(&@block)
87
+ self.run
88
88
  else
89
89
  publish(:term)
90
90
  end
@@ -28,6 +28,8 @@ module MainLoop
28
28
  # :nocov:
29
29
  end
30
30
 
31
+ # TODO поскольку wait всегда равен 5 секунд, то цикл работы 5 секунд, и потому
32
+ # timeout для Dispatcher нужно ставить больше 2 циклов, чтобы успели завершиться все потоки или процессы
31
33
  def start_loop_forever(timeout = 0)
32
34
  wait = [[(timeout / 2.5), 5].min, 5].max
33
35
  Timeouter.loop(timeout) do
@@ -98,8 +100,12 @@ module MainLoop
98
100
  results = []
99
101
 
100
102
  @dispatcher.pids.each do |pid|
101
- if (result = self.wait2(pid))
102
- results << result
103
+ begin
104
+ if (result = self.wait2(pid))
105
+ results << result
106
+ end
107
+ rescue Errno::ECHILD
108
+ results << [pid, nil]
103
109
  end
104
110
  end
105
111
 
@@ -5,13 +5,22 @@ module MainLoop
5
5
 
6
6
  attr_reader :pid
7
7
 
8
- def initialize(dispatcher, name, **kwargs, &block)
8
+ def initialize(dispatcher, name, runnable: nil, **kwargs, &block)
9
9
  super
10
10
  @handler_type = 'Process'
11
11
  @pid = nil
12
12
  dispatcher.add_handler(self)
13
13
 
14
- run(&block) if block_given?
14
+ if runnable
15
+ unless runnable.respond_to?(:run) && runnable.respond_to?(:on_term)
16
+ raise TypeError, "Runnable object must respond to :run and :on_term"
17
+ end
18
+ end
19
+
20
+ @runnable = runnable
21
+ @block = block
22
+
23
+ run
15
24
  end
16
25
 
17
26
  def id
@@ -19,10 +28,15 @@ module MainLoop
19
28
  end
20
29
 
21
30
  def reap(status)
22
- logger.info "Process[#{name}] exited: Pid:#{@pid} Status: #{status.exitstatus.inspect} Termsig: #{status.termsig.inspect} Success: #{status.success?}"
31
+ if status
32
+ logger.info "Process[#{name}] exited: Pid:#{@pid} Status: #{status.exitstatus.inspect} Termsig: #{status.termsig.inspect} Success: #{status.success?}"
33
+ @success = !!status.success?
34
+ else
35
+ logger.info "Process[#{name}] exited: Pid:#{@pid} with unknown status"
36
+ @success = true # TODO или false?
37
+ end
23
38
  @pid = nil
24
39
  @finished = true
25
- @success = !!status.success?
26
40
 
27
41
  return if terminating?
28
42
 
@@ -43,7 +57,10 @@ module MainLoop
43
57
  else
44
58
  @terminating_at ||= Time.now
45
59
  logger.info "Process[#{name}] send terminate: Pid:#{@pid}"
60
+
61
+ @runnable&.on_term(@pid) rescue nil
46
62
  @on_term&.call(@pid) rescue nil
63
+
47
64
  ::Process.kill('TERM', @pid) rescue nil
48
65
  end
49
66
  end
@@ -59,11 +76,14 @@ module MainLoop
59
76
  ::Process.kill('KILL', @pid) rescue nil
60
77
  end
61
78
 
62
- def run(&block)
79
+ def run
63
80
  return if terminating?
64
81
 
65
- @block = block
66
- start_fork(&@block)
82
+ if @runnable
83
+ start_fork { @runnable.run }
84
+ elsif @block
85
+ start_fork(&@block)
86
+ end
67
87
  end
68
88
 
69
89
  protected
@@ -71,6 +91,9 @@ module MainLoop
71
91
  def start_fork
72
92
  @pid = Kernel.fork do
73
93
  yield
94
+ rescue StandardError => e
95
+ logger.error "Process[#{name}] crashed: #{e.message}"
96
+ exit!(1)
74
97
  end
75
98
  @finished = false
76
99
  logger.info "Process[#{name}] created: Pid:#{@pid}"
@@ -79,4 +102,3 @@ module MainLoop
79
102
 
80
103
  end
81
104
  end
82
-
@@ -5,13 +5,22 @@ module MainLoop
5
5
 
6
6
  attr_reader :thread
7
7
 
8
- def initialize(dispatcher, name, **kwargs, &block)
8
+ def initialize(dispatcher, name, runnable: nil, **kwargs, &block)
9
9
  super
10
10
  @handler_type = 'Thread'
11
11
  @thread = nil
12
12
  dispatcher.add_handler(self)
13
13
 
14
- run(&block) if block_given?
14
+ if runnable
15
+ unless runnable.respond_to?(:run) && runnable.respond_to?(:on_term)
16
+ raise TypeError, "Runnable object must respond to :run and :on_term"
17
+ end
18
+ end
19
+
20
+ @runnable = runnable
21
+ @block = block
22
+
23
+ run
15
24
  end
16
25
 
17
26
  def id
@@ -44,6 +53,8 @@ module MainLoop
44
53
  @terminating_at ||= Time.now
45
54
  @success = true
46
55
  logger.info "Thread[#{name}] send terminate: thread:#{@thread}"
56
+
57
+ @runnable&.on_term(@thread) rescue nil
47
58
  @on_term&.call(@thread) rescue nil
48
59
  end
49
60
  end
@@ -59,11 +70,14 @@ module MainLoop
59
70
  @thread.kill rescue nil
60
71
  end
61
72
 
62
- def run(&block)
73
+ def run
63
74
  return if terminating?
64
75
 
65
- @block = block
66
- start_thread(&@block)
76
+ if @runnable
77
+ start_thread { @runnable.run(self) }
78
+ elsif @block
79
+ start_thread(&@block)
80
+ end
67
81
  end
68
82
 
69
83
  protected
@@ -71,6 +85,8 @@ module MainLoop
71
85
  def start_thread
72
86
  @thread = Thread.new do
73
87
  yield(self)
88
+ rescue StandardError => e
89
+ logger.error "Thread[#{name}] crashed: #{e.message}"
74
90
  ensure
75
91
  publish("reap:#{id}:exited")
76
92
  end
@@ -81,4 +97,3 @@ module MainLoop
81
97
 
82
98
  end
83
99
  end
84
-
@@ -1,6 +1,6 @@
1
1
  module MainLoop
2
2
 
3
- VERSION = '0.1.3'.freeze
3
+ VERSION = '0.1.4'.freeze
4
4
 
5
5
  end
6
6
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: main_loop
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3.16874
4
+ version: 0.1.4.364822
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samoilenko Yuri
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-09-30 00:00:00.000000000 Z
11
+ date: 2026-03-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -72,6 +72,20 @@ dependencies:
72
72
  - - ">="
73
73
  - !ruby/object:Gem::Version
74
74
  version: '0'
75
+ - !ruby/object:Gem::Dependency
76
+ name: rubycritic
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ type: :development
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
75
89
  - !ruby/object:Gem::Dependency
76
90
  name: simplecov
77
91
  requirement: !ruby/object:Gem::Requirement
@@ -100,6 +114,20 @@ dependencies:
100
114
  - - ">="
101
115
  - !ruby/object:Gem::Version
102
116
  version: '0'
117
+ - !ruby/object:Gem::Dependency
118
+ name: simplecov-cobertura
119
+ requirement: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - ">="
122
+ - !ruby/object:Gem::Version
123
+ version: '0'
124
+ type: :development
125
+ prerelease: false
126
+ version_requirements: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - ">="
129
+ - !ruby/object:Gem::Version
130
+ version: '0'
103
131
  - !ruby/object:Gem::Dependency
104
132
  name: timeouter
105
133
  requirement: !ruby/object:Gem::Requirement
@@ -135,7 +163,7 @@ homepage: https://github.com/RnD-Soft/main_loop
135
163
  licenses:
136
164
  - MIT
137
165
  metadata: {}
138
- post_install_message:
166
+ post_install_message:
139
167
  rdoc_options: []
140
168
  require_paths:
141
169
  - lib
@@ -150,8 +178,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
150
178
  - !ruby/object:Gem::Version
151
179
  version: '0'
152
180
  requirements: []
153
- rubygems_version: 3.0.3
154
- signing_key:
181
+ rubygems_version: 3.2.33
182
+ signing_key:
155
183
  specification_version: 4
156
184
  summary: Main Loop implementation to control subprocesses and threads
157
185
  test_files: []