serverengine 2.2.5 → 2.3.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 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