Skip to content

Commit 2fcb2ca

Browse files
authored
Allow Interrupt to retry the run loop after issuing #stop. (#297)
* Add Ruby v3.1 to coverage workflow.
1 parent d4409ff commit 2fcb2ca

File tree

3 files changed

+52
-9
lines changed

3 files changed

+52
-9
lines changed

.github/workflows/coverage.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ jobs:
2020
- ubuntu
2121

2222
ruby:
23+
- "3.1"
2324
- "3.2"
2425
- "ruby-head"
2526

lib/async/scheduler.rb

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -306,17 +306,22 @@ def run(...)
306306

307307
initial_task = self.async(...) if block_given?
308308

309-
# In theory, we could use Exception here to be a little bit safer, but we've only shown the case for SignalException to be a problem, so let's not over-engineer this.
310-
Thread.handle_interrupt(SignalException => :never) do
311-
while true
312-
# If we are interrupted, we need to exit:
313-
break if self.interrupted?
314-
315-
# If we are finished, we need to exit:
316-
break unless self.run_once
309+
begin
310+
# In theory, we could use Exception here to be a little bit safer, but we've only shown the case for SignalException to be a problem, so let's not over-engineer this.
311+
Thread.handle_interrupt(SignalException => :never) do
312+
while true
313+
# If we are interrupted, we need to exit:
314+
break if self.interrupted?
315+
316+
# If we are finished, we need to exit:
317+
break unless self.run_once
318+
end
317319
end
320+
rescue Interrupt
321+
self.stop
322+
retry
318323
end
319-
324+
320325
return initial_task
321326
ensure
322327
Console.logger.debug(self) {"Exiting run-loop because #{$! ? $! : 'finished'}."}

test/async/scheduler.rb

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,43 @@
8787
scheduler.close
8888
scheduler.interrupt
8989
end
90+
91+
it "can interrupt a scheduler from a different thread" do
92+
finished = false
93+
sleeping = Thread::Queue.new
94+
95+
thread = Thread.new do
96+
scheduler = Async::Scheduler.new
97+
Fiber.set_scheduler(scheduler)
98+
99+
scheduler.run do |task|
100+
sleeping.push(true)
101+
sleep
102+
ensure
103+
begin
104+
sleeping.push(true)
105+
sleep
106+
ensure
107+
finished = true
108+
end
109+
end
110+
# rescue Interrupt
111+
# # Ignore.
112+
end
113+
114+
expect(sleeping.pop).to be == true
115+
expect(finished).to be == false
116+
117+
thread.raise(Interrupt)
118+
119+
expect(sleeping.pop).to be == true
120+
expect(finished).to be == false
121+
122+
thread.raise(Interrupt)
123+
thread.join
124+
125+
expect(finished).to be == true
126+
end
90127
end
91128

92129
with '#block' do

0 commit comments

Comments
 (0)