Skip to content

Commit d97e7f6

Browse files
- mutex to correctly access hash with fiber timeouts (concurrency happens between fiber itself and iodine worker)
- kill fiber forcefully if it still alive after error was raised
1 parent 675878e commit d97e7f6

1 file changed

Lines changed: 31 additions & 20 deletions

File tree

lib/rage/fiber_scheduler.rb

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ def initialize
1111
@dns_cache = {}
1212

1313
@alive_fibers = Hash.new { |h, k| h[k] = {} }
14+
@fibers_mutex = Mutex.new
1415

1516
start_timeout_worker
1617
end
@@ -75,17 +76,21 @@ def timeout_after(duration, exception_class = Timeout::Error, *exception_argumen
7576
fiber = Fiber.current
7677
timeout_deadline = Process.clock_gettime(Process::CLOCK_MONOTONIC) + duration
7778

78-
@alive_fibers[fiber.__get_id][timeout_deadline] = {
79-
fiber: fiber,
80-
timeout_deadline: timeout_deadline,
81-
exception_class: exception_class,
82-
exception_arguments: exception_arguments
83-
}
79+
@fibers_mutex.synchronize do
80+
@alive_fibers[fiber.__get_id][timeout_deadline] = {
81+
fiber: fiber,
82+
timeout_deadline: timeout_deadline,
83+
exception_class: exception_class,
84+
exception_arguments: exception_arguments
85+
}
86+
end
8487

8588
begin
8689
block.call
8790
ensure
88-
@alive_fibers[fiber.__get_id].delete(timeout_deadline)
91+
@fibers_mutex.synchronize do
92+
@alive_fibers[fiber.__get_id].delete(timeout_deadline)
93+
end
8994
end
9095
end
9196

@@ -166,25 +171,31 @@ def start_timeout_worker
166171
end
167172

168173
def check_timeouts
169-
@alive_fibers.delete_if do |fiber_id, timeouts|
170-
timeouts.delete_if do |timeout_key, fiber_hash|
171-
current_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
174+
@fibers_mutex.synchronize do
175+
@alive_fibers.delete_if do |fiber_id, timeouts|
176+
timeouts.delete_if do |timeout_key, fiber_hash|
177+
current_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
178+
179+
next false if current_time < fiber_hash[:timeout_deadline]
172180

173-
return false if current_time < fiber_hash[:timeout_deadline]
181+
fiber = fiber_hash[:fiber]
182+
unblock(nil, fiber)
174183

175-
fiber = fiber_hash[:fiber]
176-
unblock(nil, fiber)
184+
if fiber.alive?
185+
fiber.raise(RageTimeout)
177186

178-
if fiber.alive?
179-
fiber.raise(RageTimeout)
180-
else
181-
timeouts.delete(timeout_key)
187+
::Iodine.run_after(1000) do
188+
fiber.kill if fiber.alive?
189+
end
190+
else
191+
timeouts.delete(timeout_key)
192+
end
193+
194+
true
182195
end
183196

184-
true
197+
timeouts.length == 0
185198
end
186-
187-
timeouts.length == 0
188199
end
189200
end
190201
end

0 commit comments

Comments
 (0)