serverengine 2.2.5 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2175217415cd5751a1bd4a8d60c5abdb64e80429e722c41e8c1e97ec02b1e22a
4
- data.tar.gz: 63a7af53a0dc906bb962394f902d1486f7958950c9b3b9bf41206e56789d83ad
3
+ metadata.gz: b1c09d476bdc08a078882ba14ee74f487ab988a397d2228c3e83f611fff94df1
4
+ data.tar.gz: 33732af3d1c591ec28c67249b1b67b16b142f80048f70c3cf5c769b3e267b76a
5
5
  SHA512:
6
- metadata.gz: 85880cc1ec9b83e03b2cbe80756253e156e46954117ae0a008388bfccf3d412b96a54911f9f002b6387ec2dfa9ef35dd3a40bff1dff22f7b5ca180f667d88611
7
- data.tar.gz: 624a1e6397faa39af9b871ef91571b432263d6b2b595fc4bdfaa9244a6153b25a67fe80c38c6f814c94db27b0dddcc1e4e19ae08515c8e48c2ee6208478775d0
6
+ metadata.gz: 383aaf8822f01aec3ce2e4a25243da8ca741da9d11f97c601c31cc6985e285743a088cafdd4fd918b58a966960376f65b28645b1fca74d0741e64052bd329ac8
7
+ data.tar.gz: ca10bd75948760060c8ae433cb2021a7024d6b076d84157012db5ae6809d01c9a8bb2eb2bb1f9f8d84f0881e4cbaf3bebfb25ef959130574e0cf717550ee1867
@@ -11,7 +11,7 @@ jobs:
11
11
  strategy:
12
12
  fail-fast: false
13
13
  matrix:
14
- ruby: [ '3.1', '3.0', '2.7', '2.6' ]
14
+ ruby: [ '3.1', '3.0', '2.7' ]
15
15
  os:
16
16
  - ubuntu-latest
17
17
  name: Unit testing with Ruby ${{ matrix.ruby }} on ${{ matrix.os }}
@@ -11,7 +11,7 @@ jobs:
11
11
  strategy:
12
12
  fail-fast: false
13
13
  matrix:
14
- ruby: [ '3.1', '2.7', '2.6' ]
14
+ ruby: [ '3.1', '2.7' ]
15
15
  os:
16
16
  - windows-latest
17
17
  include:
data/Changelog CHANGED
@@ -1,3 +1,15 @@
1
+ 2022-06-13 version 2.3.0
2
+
3
+ * Add restart_worker_interval option to prevent workers restart immediately
4
+ after kill
5
+ * Reopen log file when rotation done by external tool is detected
6
+ * Fix unexpected behavior of start_worker_delay option
7
+ * Remove windows-pr dependency
8
+ * Fix a potential crash that command_sender_pipe of ProcessManager::Monitor
9
+ raises error on shutdown
10
+ * Allow to load serverengine/socket_manager without servernegine/utils
11
+ * Fix unstable tests
12
+
1
13
  2022-01-13 version 2.2.5:
2
14
 
3
15
  * Fix DLL load error on Ruby 3.1 on Windows
data/README.md CHANGED
@@ -478,10 +478,11 @@ Available methods are different depending on `worker_type`. ServerEngine support
478
478
  - **disable_reload** disables USR2 signal (default: false)
479
479
  - **server_restart_wait** sets wait time before restarting server after last restarting (default: 1.0) [dynamic reloadable]
480
480
  - **server_detach_wait** sets wait time before starting live restart (default: 10.0) [dynamic reloadable]
481
- - Multithread server and multiprocess server: available only when `worker_type` is thread or process
481
+ - Multithread server and multiprocess server: available only when `worker_type` is "thread" or "process" or "spawn"
482
482
  - **workers** sets number of workers (default: 1) [dynamic reloadable]
483
- - **start_worker_delay** sets wait time before starting a new worker (default: 0) [dynamic reloadable]
483
+ - **start_worker_delay** sets the delay between each worker-start when starting/restarting multiple workers at once (default: 0) [dynamic reloadable]
484
484
  - **start_worker_delay_rand** randomizes start_worker_delay at this ratio (default: 0.2) [dynamic reloadable]
485
+ - **restart_worker_interval** sets wait time before restarting a stopped worker (default: 0) [dynamic reloadable]
485
486
  - Multiprocess server: available only when `worker_type` is "process"
486
487
  - **worker_process_name** changes process name ($0) of workers [dynamic reloadable]
487
488
  - **worker_heartbeat_interval** sets interval of heartbeats in seconds (default: 1.0) [dynamic reloadable]
data/Rakefile CHANGED
@@ -8,19 +8,3 @@ require 'rspec/core/rake_task'
8
8
 
9
9
  RSpec::Core::RakeTask.new(:spec)
10
10
  task :default => [:spec, :build]
11
-
12
- # 1. update Changelog and lib/serverengine/version.rb
13
- # 2. bundle && bundle exec rake build:all
14
- # 3. release 3 packages built on pkg/ directory
15
- namespace :build do
16
- desc 'Build gems for all platforms'
17
- task :all do
18
- Bundler.with_clean_env do
19
- %w[ruby x86-mingw32 x64-mingw32].each do |name|
20
- ENV['GEM_BUILD_FAKE_PLATFORM'] = name
21
- Rake::Task["build"].execute
22
- end
23
- end
24
- end
25
- end
26
-
@@ -55,6 +55,9 @@ module ServerEngine
55
55
  # update path string
56
56
  old_file_dev = @file_dev
57
57
  @file_dev = LogDevice.new(logdev, shift_age: @rotate_age, shift_size: @rotate_size)
58
+ # Enable to detect rotation done by external tools.
59
+ # Otherwise it continues writing logs to old file unexpectedly.
60
+ @file_dev.extend(RotationAware)
58
61
  old_file_dev.close if old_file_dev
59
62
  @logdev = @file_dev
60
63
  end
@@ -130,6 +133,40 @@ module ServerEngine
130
133
  nil
131
134
  end
132
135
 
136
+ module RotationAware
137
+ def self.extended(obj)
138
+ obj.update_ino
139
+ end
140
+
141
+ def update_ino
142
+ (@ino_mutex ||= Mutex.new).synchronize do
143
+ @ino = File.stat(filename).ino rescue nil
144
+ @last_ino_time = Time.now
145
+ end
146
+ end
147
+
148
+ def reopen(log = nil)
149
+ super(log)
150
+ update_ino
151
+ end
152
+
153
+ def reopen!
154
+ super
155
+ update_ino
156
+ end
157
+
158
+ def write(message)
159
+ reopen_needed = false
160
+ @ino_mutex.synchronize do
161
+ if (Time.now - @last_ino_time).abs > 1
162
+ ino = File.stat(filename).ino rescue nil
163
+ reopen_needed = true if ino && ino != @ino
164
+ end
165
+ end
166
+ reopen! if reopen_needed
167
+ super(message)
168
+ end
169
+ end
133
170
  end
134
171
 
135
172
  end
@@ -105,9 +105,11 @@ module ServerEngine
105
105
  @unrecoverable_exit_codes = unrecoverable_exit_codes
106
106
  @unrecoverable_exit = false
107
107
  @exitstatus = nil
108
+ @restart_at = nil
108
109
  end
109
110
 
110
111
  attr_reader :exitstatus
112
+ attr_accessor :restart_at
111
113
 
112
114
  def send_stop(stop_graceful)
113
115
  @stop = true
@@ -39,8 +39,11 @@ module ServerEngine
39
39
  def initialize(worker, thread)
40
40
  @worker = worker
41
41
  @thread = thread
42
+ @restart_at = nil
42
43
  end
43
44
 
45
+ attr_accessor :restart_at
46
+
44
47
  def send_stop(stop_graceful)
45
48
  Thread.new do
46
49
  begin
@@ -55,8 +55,8 @@ module ServerEngine
55
55
 
56
56
  def run
57
57
  while true
58
- num_alive = keepalive_workers
59
- break if num_alive == 0
58
+ num_alive_or_restarting = keepalive_workers
59
+ break if num_alive_or_restarting == 0
60
60
  wait_tick
61
61
  end
62
62
  end
@@ -85,6 +85,7 @@ module ServerEngine
85
85
 
86
86
  @start_worker_delay = @config[:start_worker_delay] || 0
87
87
  @start_worker_delay_rand = @config[:start_worker_delay_rand] || 0.2
88
+ @restart_worker_interval = @config[:restart_worker_interval] || 0
88
89
 
89
90
  scale_workers(@config[:workers] || 1)
90
91
 
@@ -96,12 +97,12 @@ module ServerEngine
96
97
  end
97
98
 
98
99
  def keepalive_workers
99
- num_alive = 0
100
+ num_alive_or_restarting = 0
100
101
 
101
102
  @monitors.each_with_index do |m,wid|
102
103
  if m && m.alive?
103
104
  # alive
104
- num_alive += 1
105
+ num_alive_or_restarting += 1
105
106
 
106
107
  elsif m && m.respond_to?(:recoverable?) && !m.recoverable?
107
108
  # exited, with unrecoverable exit code
@@ -116,8 +117,12 @@ module ServerEngine
116
117
  elsif wid < @num_workers
117
118
  # scale up or reboot
118
119
  unless @stop
119
- @monitors[wid] = delayed_start_worker(wid)
120
- num_alive += 1
120
+ if m
121
+ restart_worker(wid)
122
+ else
123
+ start_new_worker(wid)
124
+ end
125
+ num_alive_or_restarting += 1
121
126
  end
122
127
 
123
128
  elsif m
@@ -126,7 +131,27 @@ module ServerEngine
126
131
  end
127
132
  end
128
133
 
129
- return num_alive
134
+ return num_alive_or_restarting
135
+ end
136
+
137
+ def start_new_worker(wid)
138
+ delayed_start_worker(wid)
139
+ end
140
+
141
+ def restart_worker(wid)
142
+ m = @monitors[wid]
143
+
144
+ is_already_restarting = !m.restart_at.nil?
145
+ if is_already_restarting
146
+ delayed_start_worker(wid) if m.restart_at <= Time.now()
147
+ return
148
+ end
149
+
150
+ if @restart_worker_interval > 0
151
+ m.restart_at = Time.now() + @restart_worker_interval
152
+ else
153
+ delayed_start_worker(wid)
154
+ end
130
155
  end
131
156
 
132
157
  def delayed_start_worker(wid)
@@ -135,15 +160,13 @@ module ServerEngine
135
160
  Kernel.rand * @start_worker_delay * @start_worker_delay_rand -
136
161
  @start_worker_delay * @start_worker_delay_rand / 2
137
162
 
138
- now = Time.now.to_f
139
-
140
- wait = delay - (now - @last_start_worker_time)
163
+ wait = delay - (Time.now.to_f - @last_start_worker_time)
141
164
  sleep wait if wait > 0
142
165
 
143
- @last_start_worker_time = now
166
+ @last_start_worker_time = Time.now.to_f
144
167
  end
145
168
 
146
- start_worker(wid)
169
+ @monitors[wid] = start_worker(wid)
147
170
  end
148
171
  end
149
172
 
@@ -333,7 +333,15 @@ module ServerEngine
333
333
  end
334
334
 
335
335
  def send_command(command)
336
- @command_sender_pipe.write(command) if @command_sender_pipe
336
+ pid = @pid
337
+ return false unless pid
338
+
339
+ begin
340
+ @command_sender_pipe.write(command)
341
+ return true
342
+ rescue #Errno::EPIPE
343
+ return false
344
+ end
337
345
  end
338
346
 
339
347
  def try_join
@@ -80,7 +80,7 @@ module ServerEngine
80
80
  if @command_pipe
81
81
  Thread.new do
82
82
  until @command_pipe.closed?
83
- case @command_pipe.gets.chomp
83
+ case @command_pipe.gets&.chomp
84
84
  when "GRACEFUL_STOP"
85
85
  s.stop(true)
86
86
  when "IMMEDIATE_STOP"
@@ -22,6 +22,8 @@ require 'securerandom'
22
22
  require 'json'
23
23
  require 'base64'
24
24
 
25
+ require_relative 'utils' # for ServerEngine.windows?
26
+
25
27
  module ServerEngine
26
28
  module SocketManager
27
29
  # This token is used for communication between peers. If token is mismatched, messages will be discarded
@@ -1,3 +1,3 @@
1
1
  module ServerEngine
2
- VERSION = "2.2.5"
2
+ VERSION = "2.3.0"
3
3
  end
@@ -99,7 +99,6 @@ module ServerEngine
99
99
  extend Fiddle::Importer
100
100
 
101
101
  dlload "kernel32"
102
- extern "int GetModuleFileNameA(int, char *, int)"
103
102
  extern "int CloseHandle(int)"
104
103
 
105
104
  dlload RbConfig::CONFIG['LIBRUBY_SO']
data/lib/serverengine.rb CHANGED
@@ -35,12 +35,27 @@ module ServerEngine
35
35
 
36
36
  def self.ruby_bin_path
37
37
  if ServerEngine.windows?
38
- require 'windows/library'
39
- ruby_path = "\0" * 256
40
- Windows::Library::GetModuleFileName.call(0, ruby_path, 256)
41
- return ruby_path.rstrip.gsub(/\\/, '/')
38
+ ServerEngine::Win32.ruby_bin_path
42
39
  else
43
- return File.join(RbConfig::CONFIG["bindir"], RbConfig::CONFIG["RUBY_INSTALL_NAME"]) + RbConfig::CONFIG["EXEEXT"]
40
+ File.join(RbConfig::CONFIG["bindir"], RbConfig::CONFIG["RUBY_INSTALL_NAME"]) + RbConfig::CONFIG["EXEEXT"]
41
+ end
42
+ end
43
+
44
+ if ServerEngine.windows?
45
+ module Win32
46
+ require 'fiddle/import'
47
+
48
+ extend Fiddle::Importer
49
+
50
+ dlload "kernel32"
51
+ extern "int GetModuleFileNameW(int, void *, int)"
52
+
53
+ def self.ruby_bin_path
54
+ ruby_bin_path_buf = Fiddle::Pointer.malloc(1024)
55
+ len = GetModuleFileNameW(0, ruby_bin_path_buf, ruby_bin_path_buf.size / 2)
56
+ path_bytes = ruby_bin_path_buf[0, len * 2]
57
+ path_bytes.encode('UTF-8', 'UTF-16LE').gsub(/\\/, '/')
58
+ end
44
59
  end
45
60
  end
46
61
  end
data/serverengine.gemspec CHANGED
@@ -27,11 +27,5 @@ Gem::Specification.new do |gem|
27
27
  gem.add_development_dependency 'rake-compiler-dock', ['~> 0.5.0']
28
28
  gem.add_development_dependency 'rake-compiler', ['~> 0.9.4']
29
29
 
30
- # build gem for a certain platform. see also Rakefile
31
- fake_platform = ENV['GEM_BUILD_FAKE_PLATFORM'].to_s
32
- gem.platform = fake_platform unless fake_platform.empty?
33
- if /mswin|mingw/ =~ fake_platform || (/mswin|mingw/ =~ RUBY_PLATFORM && fake_platform.empty?)
34
- # windows dependencies
35
- gem.add_runtime_dependency("windows-pr", ["~> 1.2.5"])
36
- end
30
+ gem.add_development_dependency "timecop", ["~> 0.9.5"]
37
31
  end
@@ -1,4 +1,5 @@
1
1
  require 'stringio'
2
+ require 'timecop'
2
3
 
3
4
  describe ServerEngine::DaemonLogger do
4
5
  before { FileUtils.rm_rf("tmp") }
@@ -172,4 +173,28 @@ describe ServerEngine::DaemonLogger do
172
173
  $stderr = STDERR
173
174
  stderr.should_not =~ /(log shifting failed|log writing failed|log rotation inter-process lock failed)/
174
175
  end
176
+
177
+ it 'reopen log when path is renamed' do
178
+ pending "rename isn't supported on windows" if ServerEngine.windows?
179
+
180
+ log = DaemonLogger.new("tmp/rotate.log", { level: 'info', log_rotate_age: 0 })
181
+
182
+ log.info '11111'
183
+ File.read("tmp/rotate.log").should include('11111')
184
+ File.rename("tmp/rotate.log", "tmp/rotate.log.1")
185
+
186
+ Timecop.travel(Time.now + 1)
187
+
188
+ log.info '22222'
189
+ contents = File.read("tmp/rotate.log.1")
190
+ contents.should include('11111')
191
+ contents.should include('22222')
192
+
193
+ FileUtils.touch("tmp/rotate.log")
194
+ Timecop.travel(Time.now + 1)
195
+
196
+ log.info '33333'
197
+ File.read("tmp/rotate.log").should include('33333')
198
+ File.read("tmp/rotate.log.1").should_not include('33333')
199
+ end
175
200
  end
@@ -1,25 +1,208 @@
1
1
  require 'timeout'
2
+ require 'timecop'
2
3
 
3
4
  describe ServerEngine::MultiSpawnServer do
4
5
  include_context 'test server and worker'
5
6
 
6
- context 'with command_sender=pipe' do
7
- it 'starts worker processes' do
8
- config = {workers: 2, command_sender: 'pipe', log_stdout: false, log_stderr: false}
7
+ describe 'starts worker processes' do
8
+ context 'with command_sender=pipe' do
9
+ it do
10
+ config = {workers: 2, command_sender: 'pipe', log_stdout: false, log_stderr: false}
9
11
 
10
- s = ServerEngine::MultiSpawnServer.new(TestWorker) { config.dup }
11
- t = Thread.new { s.main }
12
+ s = ServerEngine::MultiSpawnServer.new(TestWorker) { config.dup }
13
+ t = Thread.new { s.main }
12
14
 
13
- begin
14
- wait_for_fork
15
+ begin
16
+ wait_for_fork
15
17
 
16
- Timeout.timeout(5) do
17
- sleep(0.5) until test_state(:worker_run) == 2
18
+ Timeout.timeout(5) do
19
+ sleep(0.5) until test_state(:worker_run) == 2
20
+ end
21
+ test_state(:worker_run).should == 2
22
+ ensure
23
+ s.stop(true)
24
+ t.join
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+ describe 'keepalive_workers' do
31
+ let(:config) {
32
+ {
33
+ workers: workers,
34
+ command_sender: 'pipe',
35
+ log_stdout: false,
36
+ log_stderr: false,
37
+ start_worker_delay: start_worker_delay,
38
+ start_worker_delay_rand: 0,
39
+ restart_worker_interval: restart_worker_interval,
40
+ }
41
+ }
42
+ let(:workers) { 3 }
43
+ let(:server) { ServerEngine::MultiSpawnServer.new(TestWorker) { config.dup } }
44
+ let(:monitors) { server.instance_variable_get(:@monitors) }
45
+
46
+ context 'default' do
47
+ let(:start_worker_delay) { 0 }
48
+ let(:restart_worker_interval) { 0 }
49
+
50
+ it do
51
+ t = Thread.new { server.main }
52
+
53
+ begin
54
+ wait_for_fork
55
+
56
+ Timeout.timeout(5) do
57
+ sleep(0.5) until monitors.count { |m| m && m.alive? } == workers
58
+ end
59
+
60
+ monitors.each do |m|
61
+ m.send_stop(true)
62
+ end
63
+
64
+ # To prevent the judge before stopping once
65
+ wait_for_stop
66
+
67
+ -> {
68
+ Timeout.timeout(5) do
69
+ sleep(0.5) until monitors.count { |m| m.alive? } == workers
70
+ end
71
+ }.should_not raise_error, "Not all workers restarted correctly."
72
+ ensure
73
+ server.stop(true)
74
+ t.join
75
+ end
76
+ end
77
+ end
78
+
79
+ context 'with only restart_worker_interval' do
80
+ let(:start_worker_delay) { 0 }
81
+ let(:restart_worker_interval) { 10 }
82
+
83
+ it do
84
+ t = Thread.new { server.main }
85
+
86
+ begin
87
+ wait_for_fork
88
+
89
+ # Wait for initial starting
90
+ Timeout.timeout(5) do
91
+ sleep(0.5) until monitors.count { |m| m && m.alive? } == workers
92
+ end
93
+
94
+ monitors.each do |m|
95
+ m.send_stop(true)
96
+ end
97
+
98
+ # Wait for all workers to stop and to be set restarting time
99
+ Timeout.timeout(5) do
100
+ sleep(0.5) until monitors.count { |m| m.alive? || m.restart_at.nil? } == 0
101
+ end
102
+
103
+ Timecop.freeze
104
+
105
+ mergin_time = 3
106
+
107
+ Timecop.freeze(Time.now + restart_worker_interval - mergin_time)
108
+ sleep(1.5)
109
+ monitors.count { |m| m.alive? }.should == 0
110
+
111
+ Timecop.freeze(Time.now + 2 * mergin_time)
112
+ -> {
113
+ Timeout.timeout(5) do
114
+ sleep(0.5) until monitors.count { |m| m.alive? } == workers
115
+ end
116
+ }.should_not raise_error, "Not all workers restarted correctly."
117
+ ensure
118
+ server.stop(true)
119
+ t.join
120
+ end
121
+ end
122
+ end
123
+
124
+ context 'with only start_worker_delay' do
125
+ let(:start_worker_delay) { 3 }
126
+ let(:restart_worker_interval) { 0 }
127
+
128
+ it do
129
+ t = Thread.new { server.main }
130
+
131
+ begin
132
+ wait_for_fork
133
+
134
+ # Initial starts are delayed too, so set longer timeout.
135
+ # (`start_worker_delay` uses `sleep` inside, so Timecop can't skip this wait.)
136
+ Timeout.timeout(start_worker_delay * workers) do
137
+ sleep(0.5) until monitors.count { |m| m && m.alive? } == workers
138
+ end
139
+
140
+ # Skip time to avoid getting a delay for the initial starts.
141
+ Timecop.travel(Time.now + start_worker_delay)
142
+
143
+ monitors.each do |m|
144
+ m.send_stop(true)
145
+ end
146
+
147
+ sleep(3)
148
+
149
+ # The first worker should restart immediately.
150
+ monitors.count { |m| m.alive? }.should satisfy { |c| 0 < c && c < workers }
151
+
152
+ # `start_worker_delay` uses `sleep` inside, so Timecop can't skip this wait.
153
+ sleep(start_worker_delay * workers)
154
+ monitors.count { |m| m.alive? }.should == workers
155
+ ensure
156
+ server.stop(true)
157
+ t.join
158
+ end
159
+ end
160
+ end
161
+
162
+ context 'with both options' do
163
+ let(:start_worker_delay) { 3 }
164
+ let(:restart_worker_interval) { 10 }
165
+
166
+ it do
167
+ t = Thread.new { server.main }
168
+
169
+ begin
170
+ wait_for_fork
171
+
172
+ # Initial starts are delayed too, so set longer timeout.
173
+ # (`start_worker_delay` uses `sleep` inside, so Timecop can't skip this wait.)
174
+ Timeout.timeout(start_worker_delay * workers) do
175
+ sleep(0.5) until monitors.count { |m| m && m.alive? } == workers
176
+ end
177
+
178
+ monitors.each do |m|
179
+ m.send_stop(true)
180
+ end
181
+
182
+ # Wait for all workers to stop and to be set restarting time
183
+ Timeout.timeout(5) do
184
+ sleep(0.5) until monitors.count { |m| m.alive? || m.restart_at.nil? } == 0
185
+ end
186
+
187
+ Timecop.freeze
188
+
189
+ mergin_time = 3
190
+
191
+ Timecop.freeze(Time.now + restart_worker_interval - mergin_time)
192
+ sleep(1.5)
193
+ monitors.count { |m| m.alive? }.should == 0
194
+
195
+ Timecop.travel(Time.now + 2 * mergin_time)
196
+ sleep(1.5)
197
+ monitors.count { |m| m.alive? }.should satisfy { |c| 0 < c && c < workers }
198
+
199
+ # `start_worker_delay` uses `sleep` inside, so Timecop can't skip this wait.
200
+ sleep(start_worker_delay * workers)
201
+ monitors.count { |m| m.alive? }.should == workers
202
+ ensure
203
+ server.stop(true)
204
+ t.join
18
205
  end
19
- test_state(:worker_run).should == 2
20
- ensure
21
- s.stop(true)
22
- t.join
23
206
  end
24
207
  end
25
208
  end
@@ -1,6 +1,7 @@
1
1
 
2
2
  require 'thread'
3
3
  require 'yaml'
4
+ require 'timecop'
4
5
 
5
6
  def reset_test_state
6
7
  FileUtils.mkdir_p 'tmp'
@@ -165,8 +166,9 @@ module TestWorker
165
166
 
166
167
  def run
167
168
  incr_test_state :worker_run
168
- 5.times do
169
- # repeats 5 times because signal handlers
169
+ # This means this worker will automatically finish after 50 seconds.
170
+ 10.times do
171
+ # repeats multiple times because signal handlers
170
172
  # interrupts wait
171
173
  @stop_flag.wait(5.0)
172
174
  end
@@ -252,16 +254,25 @@ end
252
254
 
253
255
  shared_context 'test server and worker' do
254
256
  before { reset_test_state }
257
+ after { Timecop.return }
258
+
259
+ unless self.const_defined?(:WAIT_RATIO)
260
+ if ServerEngine.windows?
261
+ WAIT_RATIO = 2
262
+ else
263
+ WAIT_RATIO = 1
264
+ end
265
+ end
255
266
 
256
267
  def wait_for_fork
257
- sleep 1.5
268
+ sleep 1.5 * WAIT_RATIO
258
269
  end
259
270
 
260
271
  def wait_for_stop
261
- sleep 0.8
272
+ sleep 0.8 * WAIT_RATIO
262
273
  end
263
274
 
264
275
  def wait_for_restart
265
- sleep 1.5
276
+ sleep 1.5 * WAIT_RATIO
266
277
  end
267
278
  end
data/spec/spec_helper.rb CHANGED
@@ -1,4 +1,9 @@
1
1
  require 'bundler'
2
+ require 'rspec'
3
+
4
+ RSpec.configure do |config|
5
+ config.color_enabled = true
6
+ end
2
7
 
3
8
  begin
4
9
  Bundler.setup(:default, :test)
data/spec/winsock_spec.rb CHANGED
@@ -1,5 +1,3 @@
1
- require 'windows/error' if ServerEngine.windows?
2
-
3
1
  describe ServerEngine::WinSock do
4
2
  # On Ruby 3.0, you need to use fiddle 1.0.8 or later to retrieve a correct
5
3
  # error code. In addition, you need to specify the path of fiddle by RUBYLIB
@@ -12,7 +10,8 @@ describe ServerEngine::WinSock do
12
10
  context 'last_error' do
13
11
  it 'bind error' do
14
12
  expect(WinSock.bind(0, nil, 0)).to be -1
15
- expect(WinSock.last_error).to be Windows::Error::WSAENOTSOCK
13
+ WSAENOTSOCK = 10038
14
+ expect(WinSock.last_error).to be WSAENOTSOCK
16
15
  end
17
16
  end
18
17
  end if ServerEngine.windows?
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: serverengine
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.5
4
+ version: 2.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sadayuki Furuhashi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-01-13 00:00:00.000000000 Z
11
+ date: 2022-06-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sigdump
@@ -80,6 +80,20 @@ dependencies:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
82
  version: 0.9.4
83
+ - !ruby/object:Gem::Dependency
84
+ name: timecop
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 0.9.5
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 0.9.5
83
97
  description: A framework to implement robust multiprocess servers like Unicorn
84
98
  email:
85
99
  - frsyuki@gmail.com
@@ -154,7 +168,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
154
168
  - !ruby/object:Gem::Version
155
169
  version: '0'
156
170
  requirements: []
157
- rubygems_version: 3.2.5
171
+ rubygems_version: 3.3.7
158
172
  signing_key:
159
173
  specification_version: 4
160
174
  summary: ServerEngine - multiprocess server framework