serverengine 2.1.1-x64-mingw32 → 2.2.4-x64-mingw32

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
- SHA1:
3
- metadata.gz: 3cafa0e1cda8c5f7d16692e4eb1678e827e0c19b
4
- data.tar.gz: 61b57f1f255d9bf3941bb8b56466f8ebc5739d36
2
+ SHA256:
3
+ metadata.gz: 40f46b384c30ca1948b502b420f3b53d92c296936f5c91bd9430f781fac08939
4
+ data.tar.gz: 3932f03c87996232a7a58645a8c77ffb2f57302f49b62c1cd6bfc944ab3e9faa
5
5
  SHA512:
6
- metadata.gz: cd7ebc97e06f60b1e098e7fb9a745192708e10896464e2cdd8caa1f7787f981c52dbcbfb079a332fe8e7db7bc70ba49b22b453e571fd93668070d45b4728de65
7
- data.tar.gz: c535ac67ea788ebd3451dcfb2f3d425ae89678b903e023260344f98535ae9b96c01df3579b3e261ec05b9852a81cf3ee631fe60c707b02a4df549ebe987653e8
6
+ metadata.gz: 34ddd5a05ef2a9f1ab41642671b57ebb76d29f9363051173d3dfc82ea3c6d735493821429710e290191effb6e553d932b2ce2fa6c9a0d0d6f407362d52c30b25
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: x64-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