serverengine 2.2.1 → 2.2.5

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: 934c5957de987807cb9a28cf740ee002cfa1c64d54c82b21acb16c464bfd8da0
4
- data.tar.gz: aef6141bd22834eb0f9fb837d374ec69b5681cb31bddc0fa1afda5cd82c3ec38
3
+ metadata.gz: 2175217415cd5751a1bd4a8d60c5abdb64e80429e722c41e8c1e97ec02b1e22a
4
+ data.tar.gz: 63a7af53a0dc906bb962394f902d1486f7958950c9b3b9bf41206e56789d83ad
5
5
  SHA512:
6
- metadata.gz: eb93190b271548e433d9dcc9ce2d7b4f8358a4bd96079b24c1417bc43e86567840733265df4931d79beacd1ba31dbe23bd1e29c1d205982e036dc29861d68c2a
7
- data.tar.gz: '09f3589a04c3bbea01c619216066e7bbb9ac2e4414cd8345713315aa416cbe2600d537bec860034423bb4566881c5febc4efb33bfd28a376953c078aeee524fb'
6
+ metadata.gz: 85880cc1ec9b83e03b2cbe80756253e156e46954117ae0a008388bfccf3d412b96a54911f9f002b6387ec2dfa9ef35dd3a40bff1dff22f7b5ca180f667d88611
7
+ data.tar.gz: 624a1e6397faa39af9b871ef91571b432263d6b2b595fc4bdfaa9244a6153b25a67fe80c38c6f814c94db27b0dddcc1e4e19ae08515c8e48c2ee6208478775d0
@@ -0,0 +1,31 @@
1
+ name: Testing on Ubuntu
2
+ on:
3
+ push:
4
+ branches: [master]
5
+ pull_request:
6
+ branches: [master]
7
+
8
+ jobs:
9
+ test:
10
+ runs-on: ${{ matrix.os }}
11
+ strategy:
12
+ fail-fast: false
13
+ matrix:
14
+ ruby: [ '3.1', '3.0', '2.7', '2.6' ]
15
+ os:
16
+ - ubuntu-latest
17
+ name: Unit testing with Ruby ${{ matrix.ruby }} on ${{ matrix.os }}
18
+ steps:
19
+ - uses: actions/checkout@v2
20
+ - name: Set up Ruby
21
+ uses: ruby/setup-ruby@v1
22
+ with:
23
+ ruby-version: ${{ matrix.ruby }}
24
+ - name: Install dependencies
25
+ run: |
26
+ gem install bundler rake
27
+ bundle install --jobs 4 --retry 3
28
+ - name: Run tests
29
+ env:
30
+ CI: true
31
+ run: bundle exec rake spec
@@ -0,0 +1,42 @@
1
+ name: Testing on Windows
2
+ on:
3
+ push:
4
+ branches: [master]
5
+ pull_request:
6
+ branches: [master]
7
+
8
+ jobs:
9
+ test:
10
+ runs-on: ${{ matrix.os }}
11
+ strategy:
12
+ fail-fast: false
13
+ matrix:
14
+ ruby: [ '3.1', '2.7', '2.6' ]
15
+ os:
16
+ - windows-latest
17
+ include:
18
+ - ruby: '3.0.3'
19
+ os: windows-latest
20
+ # On Ruby 3.0, we need to use fiddle 1.0.8 or later to retrieve correct
21
+ # error code. In addition, we have to specify the path of fiddle by RUBYLIB
22
+ # because RubyInstaller loads Ruby's bundled fiddle before initializing gem.
23
+ # See also:
24
+ # * https://github.com/ruby/fiddle/issues/72
25
+ # * https://bugs.ruby-lang.org/issues/17813
26
+ # * https://github.com/oneclick/rubyinstaller2/blob/8225034c22152d8195bc0aabc42a956c79d6c712/lib/ruby_installer/build/dll_directory.rb
27
+ ruby-lib-opt: RUBYLIB=%RUNNER_TOOL_CACHE%/Ruby/3.0.3/x64/lib/ruby/gems/3.0.0/gems/fiddle-1.1.0/lib
28
+
29
+ name: Unit testing with Ruby ${{ matrix.ruby }} on ${{ matrix.os }}
30
+ steps:
31
+ - uses: actions/checkout@v2
32
+ - name: Set up Ruby
33
+ uses: ruby/setup-ruby@v1
34
+ with:
35
+ ruby-version: ${{ matrix.ruby }}
36
+ - name: Add Fiddle 1.1.0
37
+ if: ${{ matrix.ruby == '3.0.3' }}
38
+ run: gem install fiddle --version 1.1.0
39
+ - name: Install dependencies
40
+ run: ridk exec bundle install --jobs 4 --retry 3
41
+ - name: Run tests
42
+ run: bundle exec rake spec ${{ matrix.ruby-lib-opt }}
data/Changelog CHANGED
@@ -1,3 +1,19 @@
1
+ 2022-01-13 version 2.2.5:
2
+
3
+ * Fix DLL load error on Ruby 3.1 on Windows
4
+
5
+ 2021-05-24 version 2.2.4:
6
+
7
+ * Ensure to get correct Win32 socket error on Ruby 3.0
8
+
9
+ 2021-02-17 version 2.2.3:
10
+
11
+ * Change SocketManager's port assignment strategy on Windows
12
+
13
+ 2020-11-02 version 2.2.2:
14
+
15
+ * Fix incomplete Windows support in spawn based multi worker
16
+
1
17
  2020-01-24 version 2.2.1:
2
18
 
3
19
  * Fix IPv6 dual-stack mode issue for UDP
data/NOTICE CHANGED
@@ -1,3 +1,3 @@
1
1
  ServerEngine
2
- https://github.com/frsyuki/serverengine
2
+ https://github.com/treasure-data/serverengine
3
3
  Copyright (C) 2012-2013 Sadayuki Furuhashi
@@ -120,10 +120,19 @@ module ServerEngine
120
120
  end
121
121
 
122
122
  def send_reload
123
- @pmon.send_signal(@reload_signal) if @pmon
123
+ return nil unless @pmon
124
+ if @pmon.command_sender_pipe
125
+ send_command("RELOAD\n")
126
+ else
127
+ @pmon.send_signal(@reload_signal)
128
+ end
124
129
  nil
125
130
  end
126
131
 
132
+ def send_command(command)
133
+ @pmon.send_command(command) if @pmon
134
+ end
135
+
127
136
  def join
128
137
  @pmon.join if @pmon
129
138
  nil
@@ -133,7 +142,11 @@ module ServerEngine
133
142
  return false unless @pmon
134
143
 
135
144
  if stat = @pmon.try_join
136
- @worker.logger.info "Worker #{@wid} finished#{@stop ? '' : ' unexpectedly'} with #{ServerEngine.format_join_status(stat)}"
145
+ if @stop
146
+ @worker.logger.info "Worker #{@wid} finished with #{ServerEngine.format_join_status(stat)}"
147
+ else
148
+ @worker.logger.error "Worker #{@wid} finished unexpectedly with #{ServerEngine.format_join_status(stat)}"
149
+ end
137
150
  if stat.is_a?(Process::Status) && stat.exited? && @unrecoverable_exit_codes.include?(stat.exitstatus)
138
151
  @unrecoverable_exit = true
139
152
  @exitstatus = stat.exitstatus
@@ -46,13 +46,6 @@ module ServerEngine
46
46
  @pm.command_sender = @command_sender
47
47
  end
48
48
 
49
- def stop(stop_graceful)
50
- if @command_sender == "pipe"
51
- @pm.command_sender_pipe.write(stop_graceful ? "GRACEFUL_STOP\n" : "IMMEDIATE_STOP\n")
52
- end
53
- super
54
- end
55
-
56
49
  def run
57
50
  super
58
51
  ensure
@@ -71,7 +71,6 @@ module ServerEngine
71
71
  attr_reader :enable_heartbeat, :auto_heartbeat
72
72
 
73
73
  attr_accessor :command_sender
74
- attr_reader :command_sender_pipe
75
74
 
76
75
  CONFIG_PARAMS = {
77
76
  heartbeat_interval: 1,
@@ -180,10 +179,11 @@ module ServerEngine
180
179
  end
181
180
  end
182
181
 
182
+ command_sender_pipe = nil
183
183
  if @command_sender == "pipe"
184
- inpipe, @command_sender_pipe = IO.pipe
185
- @command_sender_pipe.sync = true
186
- @command_sender_pipe.binmode
184
+ inpipe, command_sender_pipe = IO.pipe
185
+ command_sender_pipe.sync = true
186
+ command_sender_pipe.binmode
187
187
  options[:in] = inpipe
188
188
  end
189
189
  env['SERVERENGINE_SOCKETMANAGER_INTERNAL_TOKEN'] = SocketManager::INTERNAL_TOKEN
@@ -193,6 +193,7 @@ module ServerEngine
193
193
  end
194
194
 
195
195
  m = Monitor.new(pid, monitor_options)
196
+ m.command_sender_pipe = command_sender_pipe
196
197
 
197
198
  @monitors << m
198
199
 
@@ -307,9 +308,11 @@ module ServerEngine
307
308
  @graceful_kill_start_time = nil
308
309
  @immediate_kill_start_time = nil
309
310
  @kill_count = 0
311
+
312
+ @command_sender_pipe = nil
310
313
  end
311
314
 
312
- attr_accessor :last_heartbeat_time
315
+ attr_accessor :last_heartbeat_time, :command_sender_pipe
313
316
  attr_reader :pid
314
317
 
315
318
  def heartbeat_delay
@@ -329,6 +332,10 @@ module ServerEngine
329
332
  end
330
333
  end
331
334
 
335
+ def send_command(command)
336
+ @command_sender_pipe.write(command) if @command_sender_pipe
337
+ end
338
+
332
339
  def try_join
333
340
  pid = @pid
334
341
  return true unless pid
@@ -366,15 +373,25 @@ module ServerEngine
366
373
  end
367
374
 
368
375
  def start_graceful_stop!
369
- now = Time.now
370
- @next_kill_time ||= now
371
- @graceful_kill_start_time ||= now
376
+ if ServerEngine.windows?
377
+ # heartbeat isn't supported on Windows
378
+ send_command("GRACEFUL_STOP\n")
379
+ else
380
+ now = Time.now
381
+ @next_kill_time ||= now
382
+ @graceful_kill_start_time ||= now
383
+ end
372
384
  end
373
385
 
374
386
  def start_immediate_stop!
375
- now = Time.now
376
- @next_kill_time ||= now
377
- @immediate_kill_start_time ||= now
387
+ if ServerEngine.windows?
388
+ # heartbeat isn't supported on Windows
389
+ system("taskkill /f /pid #{@pid}")
390
+ else
391
+ now = Time.now
392
+ @next_kill_time ||= now
393
+ @immediate_kill_start_time ||= now
394
+ end
378
395
  end
379
396
 
380
397
  def tick(now=Time.now)
@@ -72,7 +72,10 @@ module ServerEngine
72
72
  class Server
73
73
  def self.generate_path
74
74
  if ServerEngine.windows?
75
- for port in 10000..65535
75
+ port = ENV['SERVERENGINE_SOCKETMANAGER_PORT']
76
+ return port.to_i if port
77
+
78
+ for port in get_dynamic_port_range
76
79
  if `netstat -na | findstr "#{port}"`.length == 0
77
80
  return port
78
81
  end
@@ -160,6 +163,40 @@ module ServerEngine
160
163
  ensure
161
164
  peer.close
162
165
  end
166
+
167
+ if ServerEngine.windows?
168
+ def self.valid_dynamic_port_range(start_port, end_port)
169
+ return false if start_port < 1025 or start_port > 65535
170
+ return false if end_port < 1025 or end_port > 65535
171
+ return false if start_port > end_port
172
+ true
173
+ end
174
+
175
+ def self.get_dynamic_port_range
176
+ numbers = []
177
+ # Example output of netsh (actual output is localized):
178
+ #
179
+ # Protocol tcp Dynamic Port Range
180
+ # ---------------------------------
181
+ # Start Port : 49152
182
+ # Number of Ports : 16384
183
+ #
184
+ str = `netsh int ipv4 show dynamicport tcp`.force_encoding("ASCII-8BIT")
185
+ str.each_line { |line| numbers << $1.to_i if line.match(/.*: (\d+)/) }
186
+
187
+ start_port, n_ports = numbers[0], numbers[1]
188
+ end_port = start_port + n_ports - 1
189
+
190
+ if valid_dynamic_port_range(start_port, end_port)
191
+ return start_port..end_port
192
+ else
193
+ # The default dynamic port range is 49152 - 65535 as of Windows Vista
194
+ # and Windows Server 2008.
195
+ # https://docs.microsoft.com/en-us/troubleshoot/windows-server/networking/default-dynamic-port-range-tcpip-chang
196
+ return 49152..65535
197
+ end
198
+ end
199
+ end
163
200
  end
164
201
 
165
202
  def self.send_peer(peer, obj)
@@ -1,3 +1,3 @@
1
1
  module ServerEngine
2
- VERSION = "2.2.1"
2
+ VERSION = "2.2.5"
3
3
  end
@@ -21,6 +21,7 @@ module ServerEngine
21
21
  require 'fiddle/import'
22
22
  require 'fiddle/types'
23
23
  require 'socket'
24
+ require 'rbconfig'
24
25
 
25
26
  extend Fiddle::Importer
26
27
 
@@ -78,6 +79,19 @@ module ServerEngine
78
79
  end
79
80
  end
80
81
 
82
+ def self.last_error
83
+ # On Ruby 3.0 calling WSAGetLastError here can't retrieve correct error
84
+ # code because Ruby's internal code resets it.
85
+ # See also:
86
+ # * https://github.com/ruby/fiddle/issues/72
87
+ # * https://bugs.ruby-lang.org/issues/17813
88
+ if Fiddle.respond_to?(:win32_last_socket_error)
89
+ Fiddle.win32_last_socket_error || 0
90
+ else
91
+ self.WSAGetLastError
92
+ end
93
+ end
94
+
81
95
  INVALID_SOCKET = -1
82
96
  end
83
97
 
@@ -88,18 +102,11 @@ module ServerEngine
88
102
  extern "int GetModuleFileNameA(int, char *, int)"
89
103
  extern "int CloseHandle(int)"
90
104
 
91
- ruby_bin_path_buf = Fiddle::Pointer.malloc(1000)
92
- GetModuleFileNameA(0, ruby_bin_path_buf, ruby_bin_path_buf.size)
93
-
94
- ruby_bin_path = ruby_bin_path_buf.to_s.gsub(/\\/, '/')
95
- ruby_dll_paths = File.dirname(ruby_bin_path) + '/*msvcr*ruby*.dll'
96
- ruby_dll_path = Dir.glob(ruby_dll_paths).first
97
- dlload ruby_dll_path
98
-
105
+ dlload RbConfig::CONFIG['LIBRUBY_SO']
99
106
  extern "int rb_w32_map_errno(int)"
100
107
 
101
108
  def self.raise_last_error(name)
102
- errno = rb_w32_map_errno(WinSock.WSAGetLastError)
109
+ errno = rb_w32_map_errno(WinSock.last_error)
103
110
  raise SystemCallError.new(name, errno)
104
111
  end
105
112
 
@@ -20,10 +20,16 @@ describe ServerEngine::BlockingFlag do
20
20
  it 'wait_for_set timeout' do
21
21
  start = Time.now
22
22
 
23
- subject.wait_for_set(0.01)
23
+ subject.wait_for_set(0.1)
24
24
  elapsed = Time.now - start
25
25
 
26
- elapsed.should >= 0.01
26
+ if ServerEngine.windows? && ENV['CI'] == 'True'
27
+ # timer seems low accuracy on Windows CI container, often a bit shorter
28
+ # than expected
29
+ elapsed.should >= 0.1 * 0.95
30
+ else
31
+ elapsed.should >= 0.1
32
+ end
27
33
  end
28
34
 
29
35
  it 'wait_for_reset timeout' do
@@ -31,10 +37,16 @@ describe ServerEngine::BlockingFlag do
31
37
 
32
38
  start = Time.now
33
39
 
34
- subject.wait_for_reset(0.01)
40
+ subject.wait_for_reset(0.1)
35
41
  elapsed = Time.now - start
36
42
 
37
- elapsed.should >= 0.01
43
+ if ServerEngine.windows? && ENV['CI'] == 'True'
44
+ # timer seems low accuracy on Windows CI container, often a bit shorter
45
+ # than expected
46
+ elapsed.should >= 0.1 * 0.95
47
+ else
48
+ elapsed.should >= 0.1
49
+ end
38
50
  end
39
51
 
40
52
  it 'wait' do
@@ -254,7 +254,7 @@ shared_context 'test server and worker' do
254
254
  before { reset_test_state }
255
255
 
256
256
  def wait_for_fork
257
- sleep 0.8
257
+ sleep 1.5
258
258
  end
259
259
 
260
260
  def wait_for_stop
@@ -19,7 +19,21 @@ describe ServerEngine::SocketManager do
19
19
  File.unlink(server_path) if server_path.is_a?(String) && File.exist?(server_path)
20
20
  end
21
21
 
22
- if !ServerEngine.windows?
22
+ if ServerEngine.windows?
23
+ context 'Server.generate_path' do
24
+ it 'returns socket path as port number' do
25
+ path = SocketManager::Server.generate_path
26
+ expect(path).to be_between(49152, 65535)
27
+ end
28
+
29
+ it 'can be changed via environment variable' do
30
+ ENV['SERVERENGINE_SOCKETMANAGER_PORT'] = '54321'
31
+ path = SocketManager::Server.generate_path
32
+ expect(path).to be 54321
33
+ ENV.delete('SERVERENGINE_SOCKETMANAGER_PORT')
34
+ end
35
+ end
36
+ else
23
37
  context 'Server.generate_path' do
24
38
  it 'returns socket path under /tmp' do
25
39
  path = SocketManager::Server.generate_path
@@ -191,13 +191,19 @@ describe ServerEngine::Supervisor do
191
191
  sv, t = start_supervisor(RunErrorWorker, server_restart_wait: 1, command_sender: sender)
192
192
 
193
193
  begin
194
- sleep 2.2
194
+ sleep 2.5
195
195
  ensure
196
196
  sv.stop(true)
197
197
  t.join
198
198
  end
199
199
 
200
- test_state(:worker_run).should == 3
200
+ if ServerEngine.windows?
201
+ # Because launching a process on Windows is high cost,
202
+ # it doesn't often reach to 3.
203
+ test_state(:worker_run).should <= 3
204
+ else
205
+ test_state(:worker_run).should == 3
206
+ end
201
207
  end
202
208
  end
203
209
  end
@@ -0,0 +1,18 @@
1
+ require 'windows/error' if ServerEngine.windows?
2
+
3
+ describe ServerEngine::WinSock do
4
+ # On Ruby 3.0, you need to use fiddle 1.0.8 or later to retrieve a correct
5
+ # error code. In addition, you need to specify the path of fiddle by RUBYLIB
6
+ # or `ruby -I` when you use RubyInstaller because it loads Ruby's bundled
7
+ # fiddle before initializing gem.
8
+ # See also:
9
+ # * https://github.com/ruby/fiddle/issues/72
10
+ # * https://bugs.ruby-lang.org/issues/17813
11
+ # * https://github.com/oneclick/rubyinstaller2/blob/8225034c22152d8195bc0aabc42a956c79d6c712/lib/ruby_installer/build/dll_directory.rb
12
+ context 'last_error' do
13
+ it 'bind error' do
14
+ expect(WinSock.bind(0, nil, 0)).to be -1
15
+ expect(WinSock.last_error).to be Windows::Error::WSAENOTSOCK
16
+ end
17
+ end
18
+ 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.1
4
+ version: 2.2.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sadayuki Furuhashi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-01-24 00:00:00.000000000 Z
11
+ date: 2022-01-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sigdump
@@ -87,16 +87,16 @@ executables: []
87
87
  extensions: []
88
88
  extra_rdoc_files: []
89
89
  files:
90
+ - ".github/workflows/linux.yml"
91
+ - ".github/workflows/windows.yml"
90
92
  - ".gitignore"
91
93
  - ".rspec"
92
- - ".travis.yml"
93
94
  - Changelog
94
95
  - Gemfile
95
96
  - LICENSE
96
97
  - NOTICE
97
98
  - README.md
98
99
  - Rakefile
99
- - appveyor.yml
100
100
  - examples/server.rb
101
101
  - examples/spawn_worker_script.rb
102
102
  - lib/serverengine.rb
@@ -134,6 +134,7 @@ files:
134
134
  - spec/socket_manager_spec.rb
135
135
  - spec/spec_helper.rb
136
136
  - spec/supervisor_spec.rb
137
+ - spec/winsock_spec.rb
137
138
  homepage: https://github.com/fluent/serverengine
138
139
  licenses:
139
140
  - Apache 2.0
@@ -153,7 +154,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
153
154
  - !ruby/object:Gem::Version
154
155
  version: '0'
155
156
  requirements: []
156
- rubygems_version: 3.0.3
157
+ rubygems_version: 3.2.5
157
158
  signing_key:
158
159
  specification_version: 4
159
160
  summary: ServerEngine - multiprocess server framework
@@ -168,3 +169,4 @@ test_files:
168
169
  - spec/socket_manager_spec.rb
169
170
  - spec/spec_helper.rb
170
171
  - spec/supervisor_spec.rb
172
+ - spec/winsock_spec.rb
data/.travis.yml DELETED
@@ -1,22 +0,0 @@
1
- language: ruby
2
-
3
- rvm:
4
- - 2.1.10
5
- - 2.2.9
6
- - 2.3.8
7
- - 2.4.5
8
- - 2.5.3
9
- - ruby-head
10
-
11
- branches:
12
- only:
13
- - master
14
-
15
- script: bundle exec rake spec
16
-
17
- before_install:
18
- - gem update bundler
19
-
20
- matrix:
21
- allow_failures:
22
- - rvm: ruby-head
data/appveyor.yml DELETED
@@ -1,24 +0,0 @@
1
- ---
2
- install:
3
- - SET PATH=C:\Ruby%ruby_version%\bin;%PATH%
4
- - ruby --version
5
- - gem --version
6
- - bundle install
7
- build: off
8
- test_script:
9
- - bundle exec rake -rdevkit
10
-
11
- environment:
12
- matrix:
13
- - ruby_version: "23-x64"
14
- devkit: C:\Ruby23-x64\DevKit
15
- - ruby_version: "23"
16
- devkit: C:\Ruby23\DevKit
17
- - ruby_version: "22-x64"
18
- devkit: C:\Ruby23-x64\DevKit
19
- - ruby_version: "22"
20
- devkit: C:\Ruby23\DevKit
21
- - ruby_version: "21-x64"
22
- devkit: C:\Ruby23-x64\DevKit
23
- - ruby_version: "21"
24
- devkit: C:\Ruby23\DevKit