serverengine 2.1.1-x86-mingw32 → 2.2.4-x86-mingw32

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
- SHA1:
3
- metadata.gz: 6069f9499ee36cc5cd176e6b446c7f7c7df69c59
4
- data.tar.gz: 61b57f1f255d9bf3941bb8b56466f8ebc5739d36
2
+ SHA256:
3
+ metadata.gz: 14225458f5959eab0eefdff088da3f289816a4f0e9e871e291edbeb7aa1796df
4
+ data.tar.gz: 3932f03c87996232a7a58645a8c77ffb2f57302f49b62c1cd6bfc944ab3e9faa
5
5
  SHA512:
6
- metadata.gz: ba047c51a6dc3abccf056dbdd0388283ded565e06c802dd73b83ceab7f2e242cdf58e3684bfe0d8b827e483d965e327ff6f881951526a4a8d205a05337631bb2
7
- data.tar.gz: c535ac67ea788ebd3451dcfb2f3d425ae89678b903e023260344f98535ae9b96c01df3579b3e261ec05b9852a81cf3ee631fe60c707b02a4df549ebe987653e8
6
+ metadata.gz: 6db094c6723490b9f4fba7d62bc70a52239aa22f4b9ac3f598d2b734d70052b27460be326283be3f84107127749cf2ed957e1a6f6ad8b0a7cfe731103cc2531c
7
+ data.tar.gz: 2982698d8a5762b8305f20d92f4e0d8766db9ee735a33a6a3b01c192414fd9a5f9492176e26afab848d9a986d35827cf4a84c14850f7094a69323b860d32bf60
@@ -0,0 +1,26 @@
1
+ name: Testing on Ubuntu
2
+ on:
3
+ - push
4
+ - pull_request
5
+ jobs:
6
+ build:
7
+ runs-on: ${{ matrix.os }}
8
+ strategy:
9
+ fail-fast: false
10
+ matrix:
11
+ ruby: [ '3.0', '2.7', '2.6', '2.5' ]
12
+ os:
13
+ - ubuntu-latest
14
+ name: Ruby ${{ matrix.ruby }} unit testing on ${{ matrix.os }}
15
+ steps:
16
+ - uses: actions/checkout@v2
17
+ - uses: ruby/setup-ruby@v1
18
+ with:
19
+ ruby-version: ${{ matrix.ruby }}
20
+ - name: unit testing
21
+ env:
22
+ CI: true
23
+ run: |
24
+ gem install bundler rake
25
+ bundle install --jobs 4 --retry 3
26
+ bundle exec rake spec
data/Changelog CHANGED
@@ -1,3 +1,24 @@
1
+ 2021-05-24 version 2.2.4:
2
+
3
+ * Ensure to get correct Win32 socket error on Ruby 3.0
4
+
5
+ 2021-02-17 version 2.2.3:
6
+
7
+ * Change SocketManager's port assignment strategy on Windows
8
+
9
+ 2020-11-02 version 2.2.2:
10
+
11
+ * Fix incomplete Windows support in spawn based multi worker
12
+
13
+ 2020-01-24 version 2.2.1:
14
+
15
+ * Fix IPv6 dual-stack mode issue for UDP
16
+ * experimental: Add SERVERENGINE_USE_SOCKET_REUSEPORT envvar to enable SO_REUSEPORT
17
+
18
+ 2019-11-16 version 2.2.0:
19
+
20
+ * Fix IPv6 dual-stack mode issue for TCP
21
+
1
22
  2019-04-22 version 2.1.1:
2
23
 
3
24
  * Fix bug to ignore SIGDUMP_SIGNAL
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
data/appveyor.yml CHANGED
@@ -1,4 +1,6 @@
1
1
  ---
2
+ image: Visual Studio 2019
3
+
2
4
  install:
3
5
  - SET PATH=C:\Ruby%ruby_version%\bin;%PATH%
4
6
  - ruby --version
@@ -6,19 +8,28 @@ install:
6
8
  - bundle install
7
9
  build: off
8
10
  test_script:
9
- - bundle exec rake -rdevkit
11
+ - bundle exec rake spec
10
12
 
11
13
  environment:
12
14
  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
15
+ - ruby_version: "30-x64"
16
+ - ruby_version: "27-x64"
17
+ - ruby_version: "26-x64"
18
+ - ruby_version: "25-x64"
19
+
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
+ for:
28
+ -
29
+ matrix:
30
+ only:
31
+ - ruby_version: "30-x64"
32
+ test_script:
33
+ - gem install fiddle --version 1.0.8
34
+ - set RUBYLIB=C:/Ruby%ruby_version%/lib/ruby/gems/3.0.0/gems/fiddle-1.0.8/lib
35
+ - bundle exec rake spec
@@ -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
@@ -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)
@@ -67,7 +67,7 @@ module ServerEngine
67
67
 
68
68
  def signal_handler_main(sig)
69
69
  # here always creates new thread to avoid
70
- # complicated race conditin in signal handlers
70
+ # complicated race condition in signal handlers
71
71
  Thread.new do
72
72
  begin
73
73
  enqueue(sig)
@@ -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)
@@ -50,19 +50,30 @@ module ServerEngine
50
50
  private
51
51
 
52
52
  def listen_tcp_new(bind_ip, port)
53
- sock = TCPServer.new(bind_ip.to_s, port)
54
- sock.listen(Socket::SOMAXCONN) # TODO make backlog configurable if necessary
55
- return sock
53
+ if ENV['SERVERENGINE_USE_SOCKET_REUSEPORT'] == '1'
54
+ # Based on Addrinfo#listen
55
+ tsock = Socket.new(bind_ip.ipv6? ? ::Socket::AF_INET6 : ::Socket::AF_INET, ::Socket::SOCK_STREAM, 0)
56
+ tsock.ipv6only! if bind_ip.ipv6?
57
+ tsock.setsockopt(:SOCKET, :REUSEPORT, true)
58
+ tsock.setsockopt(:SOCKET, :REUSEADDR, true)
59
+ tsock.bind(Addrinfo.tcp(bind_ip.to_s, port))
60
+ tsock.listen(::Socket::SOMAXCONN)
61
+ tsock.autoclose = false
62
+ TCPServer.for_fd(tsock.fileno)
63
+ else
64
+ # TCPServer.new doesn't set IPV6_V6ONLY flag, so use Addrinfo class instead.
65
+ # TODO: make backlog configurable if necessary
66
+ tsock = Addrinfo.tcp(bind_ip.to_s, port).listen(::Socket::SOMAXCONN)
67
+ tsock.autoclose = false
68
+ TCPServer.for_fd(tsock.fileno)
69
+ end
56
70
  end
57
71
 
58
72
  def listen_udp_new(bind_ip, port)
59
- if bind_ip.ipv6?
60
- sock = UDPSocket.new(Socket::AF_INET6)
61
- else
62
- sock = UDPSocket.new(Socket::AF_INET)
63
- end
64
- sock.bind(bind_ip.to_s, port)
65
- return sock
73
+ # UDPSocket.new doesn't set IPV6_V6ONLY flag, so use Addrinfo class instead.
74
+ usock = Addrinfo.udp(bind_ip.to_s, port).bind
75
+ usock.autoclose = false
76
+ UDPSocket.for_fd(usock.fileno)
66
77
  end
67
78
 
68
79
  def start_server(path)
@@ -1,3 +1,3 @@
1
1
  module ServerEngine
2
- VERSION = "2.1.1"
2
+ VERSION = "2.2.4"
3
3
  end
@@ -78,6 +78,19 @@ module ServerEngine
78
78
  end
79
79
  end
80
80
 
81
+ def self.last_error
82
+ # On Ruby 3.0 calling WSAGetLastError here can't retrieve correct error
83
+ # code because Ruby's internal code resets it.
84
+ # See also:
85
+ # * https://github.com/ruby/fiddle/issues/72
86
+ # * https://bugs.ruby-lang.org/issues/17813
87
+ if Fiddle.respond_to?(:win32_last_socket_error)
88
+ Fiddle.win32_last_socket_error || 0
89
+ else
90
+ self.WSAGetLastError
91
+ end
92
+ end
93
+
81
94
  INVALID_SOCKET = -1
82
95
  end
83
96
 
@@ -99,7 +112,7 @@ module ServerEngine
99
112
  extern "int rb_w32_map_errno(int)"
100
113
 
101
114
  def self.raise_last_error(name)
102
- errno = rb_w32_map_errno(WinSock.WSAGetLastError)
115
+ errno = rb_w32_map_errno(WinSock.last_error)
103
116
  raise SystemCallError.new(name, errno)
104
117
  end
105
118
 
@@ -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
@@ -155,7 +169,27 @@ describe ServerEngine::SocketManager do
155
169
  test_state(:is_udp_socket).should == 1
156
170
  test_state(:udp_data_sent).should == 1
157
171
  end
158
- end if (TCPServer.open("::1",0) rescue nil)
172
+ end if (TCPServer.open("::1", 0) rescue nil)
173
+
174
+ unless ServerEngine.windows?
175
+ context 'using ipv4/ipv6' do
176
+ it 'can bind ipv4/ipv6 together' do
177
+ server = SocketManager::Server.open(server_path)
178
+ client = ServerEngine::SocketManager::Client.new(server_path)
179
+
180
+ tcp_v4 = client.listen_tcp('0.0.0.0', test_port)
181
+ udp_v4 = client.listen_udp('0.0.0.0', test_port)
182
+ tcp_v6 = client.listen_tcp('::', test_port)
183
+ udp_v6 = client.listen_udp('::', test_port)
184
+
185
+ tcp_v4.close
186
+ udp_v4.close
187
+ tcp_v6.close
188
+ udp_v6.close
189
+ server.close
190
+ end
191
+ end if (TCPServer.open("::", 0) rescue nil)
192
+ end
159
193
  end
160
194
 
161
195
  if ServerEngine.windows?
@@ -191,7 +191,7 @@ 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
@@ -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.1.1
4
+ version: 2.2.4
5
5
  platform: x86-mingw32
6
6
  authors:
7
7
  - Sadayuki Furuhashi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-04-23 00:00:00.000000000 Z
11
+ date: 2021-05-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sigdump
@@ -101,9 +101,9 @@ executables: []
101
101
  extensions: []
102
102
  extra_rdoc_files: []
103
103
  files:
104
+ - ".github/workflows/linux.yml"
104
105
  - ".gitignore"
105
106
  - ".rspec"
106
- - ".travis.yml"
107
107
  - Changelog
108
108
  - Gemfile
109
109
  - LICENSE
@@ -148,6 +148,7 @@ files:
148
148
  - spec/socket_manager_spec.rb
149
149
  - spec/spec_helper.rb
150
150
  - spec/supervisor_spec.rb
151
+ - spec/winsock_spec.rb
151
152
  homepage: https://github.com/fluent/serverengine
152
153
  licenses:
153
154
  - Apache 2.0
@@ -167,8 +168,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
167
168
  - !ruby/object:Gem::Version
168
169
  version: '0'
169
170
  requirements: []
170
- rubyforge_project:
171
- rubygems_version: 2.6.14.1
171
+ rubygems_version: 3.2.5
172
172
  signing_key:
173
173
  specification_version: 4
174
174
  summary: ServerEngine - multiprocess server framework
@@ -183,3 +183,4 @@ test_files:
183
183
  - spec/socket_manager_spec.rb
184
184
  - spec/spec_helper.rb
185
185
  - spec/supervisor_spec.rb
186
+ - 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