polyphony 0.43.2 → 0.43.3

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: c7cf8c345b125c9a41ca7c0ad025ac21d001fc1f73dedb0b4968e426a096d8b6
4
- data.tar.gz: 23b828449792dc3887c75ad54da3451696de66f6aceee255d8a1a5e9489bdf90
3
+ metadata.gz: f48ef7d009af377b337388a1cca2eb4fe16b85deb1f37076fcd40e010aa9c0e3
4
+ data.tar.gz: 7b4fa6e8951dc52fd3fdcc9b5a2f1974155e2b709d71de593657374de5020c88
5
5
  SHA512:
6
- metadata.gz: a35a60f273a1989d31155a0d9c6d0a3685794dc363cb60fbf77cce4f8d4f15f7c16c6489d63d4534dc20b281fe0a9aa65f036ffa478e689d119679db48d7a52f
7
- data.tar.gz: 8de219230c3a1ae3a6c7b618d271a58c54abe8ab5208a338e935c823056b6edebf6d311b4d90748ca9aad238f6b67643a3ac71036a60700920859bcffde56acd
6
+ metadata.gz: 8de0f7526767acef9487417efb79c528312905adc4daed2664e8781ddfffa82118812407c2632269f8c6df0ba91733723804bad027e67cd5094aa1855241d8b4
7
+ data.tar.gz: 94f5f80ec12f9fba315ce76495f7792125190a2e2004b455a79d58912cac523cd07f90f62218823126023a4003e4f08281676d899737f30d271d5c981f191d04
@@ -7,7 +7,7 @@ jobs:
7
7
  strategy:
8
8
  fail-fast: false
9
9
  matrix:
10
- os: [ubuntu-latest, macos-latest]
10
+ os: [ubuntu-latest]
11
11
  ruby: [2.6, 2.7]
12
12
 
13
13
  name: >-
@@ -1,3 +1,10 @@
1
+ ## 0.43.3 2020-07-08
2
+
3
+ * Fix behaviour after call to `Process.daemon` (#8)
4
+ * Replace core `Queue` class with `Polyphony::Queue` (#22)
5
+ * Make `ResourcePool` reentrant (#1)
6
+ * Accept `:with_exception` argument in `cancel_after` (#16)
7
+
1
8
  ## 0.43.2 2020-07-07
2
9
 
3
10
  * Fix sending Redis commands with array arguments (#21)
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- polyphony (0.43.2)
4
+ polyphony (0.43.3)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -12,7 +12,7 @@ GEM
12
12
  ast (2.4.0)
13
13
  builder (3.2.4)
14
14
  colorator (1.1.0)
15
- concurrent-ruby (1.1.5)
15
+ concurrent-ruby (1.1.6)
16
16
  docile (1.3.2)
17
17
  em-websocket (0.5.1)
18
18
  eventmachine (>= 0.12.9)
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'polyphony'
5
+ require 'concurrent'
6
+
7
+ puts "Hello, concurrent-ruby"
8
+
9
+ # this program should not hang with concurrent-ruby 1.1.6 (see issue #22)
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'polyphony'
5
+
6
+ Exception.__disable_sanitized_backtrace__ = true
7
+
8
+ puts "pid: #{Process.pid}"
9
+
10
+ Process.daemon(true, true)
11
+
12
+ Polyphony::ThreadPool.process do
13
+ puts "Hello world from pid #{Process.pid}"
14
+ end
@@ -6,6 +6,12 @@ require_relative './polyphony_ext'
6
6
  module Polyphony
7
7
  # Map Queue to Libev queue implementation
8
8
  Queue = LibevQueue
9
+
10
+ # replace core Queue class with our own
11
+ verbose = $VERBOSE
12
+ $VERBOSE = nil
13
+ Object.const_set(:Queue, Polyphony::Queue)
14
+ $VERBOSE = verbose
9
15
  end
10
16
 
11
17
  require_relative './polyphony/extensions/core'
@@ -114,7 +120,25 @@ module Polyphony
114
120
  threads.each(&:kill)
115
121
  threads.each(&:join)
116
122
  end
123
+
124
+ attr_accessor :original_pid
125
+
126
+ def install_at_exit_handler
127
+ @original_pid = ::Process.pid
128
+
129
+ # This at_exit handler is needed only when the original process exits. Due to
130
+ # the behaviour of fibers on fork (and especially on exit from forked
131
+ # processes,) we use a separate mechanism to terminate fibers in forked
132
+ # processes (see Polyphony.fork).
133
+ at_exit do
134
+ next unless @original_pid == ::Process.pid
135
+
136
+ Polyphony.terminate_threads
137
+ Fiber.current.shutdown_all_children
138
+ end
139
+ end
117
140
  end
118
141
  end
119
142
 
120
143
  Polyphony.install_terminating_signal_handlers
144
+ Polyphony.install_at_exit_handler
@@ -15,11 +15,13 @@ module Polyphony
15
15
  end
16
16
  end
17
17
 
18
- def cancel_after(interval, &block)
18
+ def cancel_after(interval, with_exception: Polyphony::Cancel, &block)
19
19
  fiber = ::Fiber.current
20
20
  canceller = spin do
21
21
  sleep interval
22
- fiber.schedule Polyphony::Cancel.new
22
+ exception = with_exception.is_a?(Class) ?
23
+ with_exception.new : RuntimeError.new(with_exception)
24
+ fiber.schedule exception
23
25
  end
24
26
  block ? cancel_after_wrap_block(canceller, &block) : canceller
25
27
  end
@@ -13,6 +13,7 @@ module Polyphony
13
13
 
14
14
  @stock = []
15
15
  @queue = []
16
+ @acquired_resources = {}
16
17
 
17
18
  @limit = opts[:limit] || 4
18
19
  @size = 0
@@ -23,16 +24,25 @@ module Polyphony
23
24
  end
24
25
 
25
26
  def acquire
26
- Thread.current.agent.ref
27
- resource = wait_for_resource
28
- return unless resource
29
-
30
- yield resource
31
- ensure
32
- Thread.current.agent.unref
33
- release(resource) if resource
27
+ fiber = Fiber.current
28
+ if @acquired_resources[fiber]
29
+ yield @acquired_resources[fiber]
30
+ else
31
+ begin
32
+ Thread.current.agent.ref
33
+ resource = wait_for_resource
34
+ return unless resource
35
+
36
+ @acquired_resources[fiber] = resource
37
+ yield resource
38
+ ensure
39
+ @acquired_resources[fiber] = nil
40
+ Thread.current.agent.unref
41
+ release(resource) if resource
42
+ end
43
+ end
34
44
  end
35
-
45
+
36
46
  def wait_for_resource
37
47
  fiber = Fiber.current
38
48
  @queue << fiber
@@ -57,6 +57,12 @@ module ::Process
57
57
  fiber.define_singleton_method(:pid) { pid }
58
58
  fiber
59
59
  end
60
+
61
+ alias_method :orig_daemon, :daemon
62
+ def daemon(*args)
63
+ orig_daemon(*args)
64
+ Polyphony.original_pid = Process.pid
65
+ end
60
66
  end
61
67
  end
62
68
 
@@ -370,15 +370,3 @@ class ::Fiber
370
370
  end
371
371
 
372
372
  Fiber.current.setup_main_fiber
373
-
374
- # This at_exit handler is needed only when the original process exits. Due to
375
- # the behaviour of fibers on fork (and especially on exit from forked
376
- # processes,) we use a separate mechanism to terminate fibers in forked
377
- # processes (see Polyphony.fork).
378
- orig_pid = Process.pid
379
- at_exit do
380
- next unless orig_pid == Process.pid
381
-
382
- Polyphony.terminate_threads
383
- Fiber.current.shutdown_all_children
384
- end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Polyphony
4
- VERSION = '0.43.2'
4
+ VERSION = '0.43.3'
5
5
  end
@@ -111,12 +111,12 @@ class AgentTest < MiniTest::Test
111
111
  end
112
112
 
113
113
  c1 = TCPSocket.new('127.0.0.1', 1234)
114
- snooze
114
+ 10.times { snooze }
115
115
 
116
116
  assert_equal 1, clients.size
117
117
 
118
118
  c2 = TCPSocket.new('127.0.0.1', 1234)
119
- 2.times { snooze }
119
+ 10.times { snooze }
120
120
 
121
121
  assert_equal 2, clients.size
122
122
 
@@ -482,9 +482,9 @@ class FiberTest < MiniTest::Test
482
482
  def test_select_from_multiple_fibers
483
483
  sleep 0
484
484
  buffer = []
485
- f1 = spin { sleep 0.01; buffer << :foo; :foo }
486
- f2 = spin { sleep 0.03; buffer << :bar; :bar }
487
- f3 = spin { sleep 0.05; buffer << :baz; :baz }
485
+ f1 = spin { sleep 0.1; buffer << :foo; :foo }
486
+ f2 = spin { sleep 0.3; buffer << :bar; :bar }
487
+ f3 = spin { sleep 0.5; buffer << :baz; :baz }
488
488
 
489
489
  selected, result = Fiber.select(f1, f2, f3)
490
490
  assert_equal :foo, result
@@ -106,7 +106,7 @@ class MoveOnAfterTest < MiniTest::Test
106
106
  end
107
107
  t1 = Time.now
108
108
 
109
- assert t1 - t0 < 0.03
109
+ assert t1 - t0 < 0.1
110
110
  assert_nil v
111
111
  end
112
112
 
@@ -118,7 +118,7 @@ class MoveOnAfterTest < MiniTest::Test
118
118
  end
119
119
  t1 = Time.now
120
120
 
121
- assert t1 - t0 < 0.02
121
+ assert t1 - t0 < 0.1
122
122
  assert_equal :bar, v
123
123
  end
124
124
 
@@ -129,7 +129,7 @@ class MoveOnAfterTest < MiniTest::Test
129
129
  assert_equal Fiber.current, f.parent
130
130
  v = sleep 1
131
131
  t1 = Time.now
132
- assert t1 - t0 < 0.02
132
+ assert t1 - t0 < 0.1
133
133
  assert_equal 'foo', v
134
134
  end
135
135
  end
@@ -159,6 +159,30 @@ class CancelAfterTest < MiniTest::Test
159
159
  t1 = Time.now
160
160
  assert t1 - t0 < 0.1
161
161
  end
162
+
163
+ class CustomException < Exception
164
+ end
165
+
166
+ def test_cancel_after_with_custom_exception
167
+ assert_raises CustomException do
168
+ cancel_after(0.01, with_exception: CustomException) do
169
+ sleep 1
170
+ :foo
171
+ end
172
+ end
173
+
174
+ begin
175
+ e = nil
176
+ cancel_after(0.01, with_exception: 'foo') do
177
+ sleep 1
178
+ :foo
179
+ end
180
+ rescue => e
181
+ ensure
182
+ assert_kind_of RuntimeError, e
183
+ assert_equal 'foo', e.message
184
+ end
185
+ end
162
186
  end
163
187
 
164
188
 
@@ -201,10 +225,13 @@ class SpinLoopTest < MiniTest::Test
201
225
  def test_spin_loop_with_rate
202
226
  buffer = []
203
227
  counter = 0
204
- f = spin_loop(rate: 50) { buffer << (counter += 1) }
228
+ t0 = Time.now
229
+ f = spin_loop(rate: 10) { buffer << (counter += 1) }
205
230
  sleep 0.2
206
231
  f.stop
207
- assert counter >= 9 && counter <= 11
232
+ elapsed = Time.now - t0
233
+ expected = (elapsed * 10).to_i
234
+ assert counter >= expected - 1 && counter <= expected + 1
208
235
  end
209
236
  end
210
237
 
@@ -212,12 +239,15 @@ class ThrottledLoopTest < MiniTest::Test
212
239
  def test_throttled_loop
213
240
  buffer = []
214
241
  counter = 0
242
+ t0 = Time.now
215
243
  f = spin do
216
- throttled_loop(50) { buffer << (counter += 1) }
244
+ throttled_loop(10) { buffer << (counter += 1) }
217
245
  end
218
- sleep 0.2
246
+ sleep 0.3
219
247
  f.stop
220
- assert counter >= 9 && counter <= 11
248
+ elapsed = Time.now - t0
249
+ expected = (elapsed * 10).to_i
250
+ assert counter >= expected - 1 && counter <= expected + 1
221
251
  end
222
252
 
223
253
  def test_throttled_loop_with_count
@@ -243,19 +273,22 @@ class GlobalAPIEtcTest < MiniTest::Test
243
273
 
244
274
  def test_every
245
275
  buffer = []
276
+ t0 = Time.now
246
277
  f = spin do
247
- every(0.01) { buffer << 1 }
278
+ every(0.1) { buffer << 1 }
248
279
  end
249
- sleep 0.05
280
+ sleep 0.5
250
281
  f.stop
251
- assert (4..5).include?(buffer.size)
282
+ elapsed = Time.now - t0
283
+ expected = (elapsed / 0.1).to_i
284
+ assert buffer.size >= expected - 2 && buffer.size <= expected + 2
252
285
  end
253
286
 
254
287
  def test_sleep
255
288
  t0 = Time.now
256
- sleep 0.05
289
+ sleep 0.1
257
290
  elapsed = Time.now - t0
258
- assert (0.045..0.08).include? elapsed
291
+ assert (0.05..0.15).include? elapsed
259
292
 
260
293
  f = spin { sleep }
261
294
  snooze
@@ -123,4 +123,16 @@ class ResourcePoolTest < MiniTest::Test
123
123
  pool.preheat!
124
124
  assert_equal 2, pool.size
125
125
  end
126
+
127
+ def test_reentrant_resource_pool
128
+ resources = [+'a', +'b']
129
+ pool = Polyphony::ResourcePool.new(limit: 1) { resources.shift }
130
+
131
+ pool.acquire do |r|
132
+ assert_equal 'a', r
133
+ pool.acquire do |r|
134
+ assert_equal 'a', r
135
+ end
136
+ end
137
+ end
126
138
  end
@@ -4,14 +4,15 @@ require_relative 'helper'
4
4
 
5
5
  class ThrottlerTest < MiniTest::Test
6
6
  def test_throttler_with_rate
7
- t = Polyphony::Throttler.new(100)
7
+ t = Polyphony::Throttler.new(10)
8
8
  buffer = []
9
+ t0 = Time.now
9
10
  f = spin { loop { t.process { buffer << 1 } } }
10
- sleep 0.02
11
+ sleep 0.2
11
12
  f.stop
12
- snooze
13
- assert buffer.size >= 2
14
- assert buffer.size <= 3
13
+ elapsed = Time.now - t0
14
+ expected = (elapsed * 10).to_i
15
+ assert buffer.size >= expected - 1 && buffer.size <= expected + 1
15
16
  ensure
16
17
  t.stop
17
18
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: polyphony
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.43.2
4
+ version: 0.43.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sharon Rosner
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-07-07 00:00:00.000000000 Z
11
+ date: 2020-07-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: httparty
@@ -280,6 +280,7 @@ files:
280
280
  - docs/main-concepts/fiber-scheduling.md
281
281
  - docs/main-concepts/index.md
282
282
  - docs/polyphony-logo.png
283
+ - examples/adapters/concurrent-ruby.rb
283
284
  - examples/adapters/pg_client.rb
284
285
  - examples/adapters/pg_notify.rb
285
286
  - examples/adapters/pg_pool.rb
@@ -297,6 +298,7 @@ files:
297
298
  - examples/core/xx-at_exit.rb
298
299
  - examples/core/xx-caller.rb
299
300
  - examples/core/xx-channels.rb
301
+ - examples/core/xx-daemon.rb
300
302
  - examples/core/xx-deadlock.rb
301
303
  - examples/core/xx-deferring-an-operation.rb
302
304
  - examples/core/xx-erlang-style-genserver.rb