From a8738f15dd82bef635bbb7feb335f60f3bad4877 Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Tue, 2 Jan 2024 21:38:16 +1300 Subject: [PATCH 1/5] Allow Interrupt to retry the run loop after issuing #stop. --- lib/async/scheduler.rb | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/lib/async/scheduler.rb b/lib/async/scheduler.rb index ec38fb26..accf41e9 100644 --- a/lib/async/scheduler.rb +++ b/lib/async/scheduler.rb @@ -306,17 +306,22 @@ def run(...) initial_task = self.async(...) if block_given? - # 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. - Thread.handle_interrupt(SignalException => :never) do - while true - # If we are interrupted, we need to exit: - break if self.interrupted? - - # If we are finished, we need to exit: - break unless self.run_once + begin + # 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. + Thread.handle_interrupt(SignalException => :never) do + while true + # If we are interrupted, we need to exit: + break if self.interrupted? + + # If we are finished, we need to exit: + break unless self.run_once + end end + rescue Interrupt + self.stop + retry end - + return initial_task ensure Console.logger.debug(self) {"Exiting run-loop because #{$! ? $! : 'finished'}."} From 4133fde56b8dae7a6512d220f49c280a2162dd08 Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Wed, 3 Jan 2024 13:13:25 +1300 Subject: [PATCH 2/5] Add test for Interrupt handling. --- test/async/scheduler.rb | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/test/async/scheduler.rb b/test/async/scheduler.rb index 1a34e910..26bc158b 100644 --- a/test/async/scheduler.rb +++ b/test/async/scheduler.rb @@ -87,6 +87,41 @@ scheduler.close scheduler.interrupt end + + it "can interrupt a scheduler from a different thread" do + scheduler = Async::Scheduler.new + finished = false + sleeping = Thread::Queue.new + + thread = Thread.new do + scheduler.run do |task| + sleeping.push(true) + sleep + ensure + begin + sleeping.push(true) + sleep + ensure + finished = true + end + end + rescue Interrupt + # Ignore. + end + + expect(sleeping.pop).to be == true + expect(finished).to be == false + + thread.raise(Interrupt) + + expect(sleeping.pop).to be == true + expect(finished).to be == false + + thread.raise(Interrupt) + thread.join + + expect(finished).to be == true + end end with '#block' do From 9076aac576d385c125c377478fd5b94f3a40db93 Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Wed, 3 Jan 2024 14:01:25 +1300 Subject: [PATCH 3/5] Fix test. --- test/async/scheduler.rb | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/test/async/scheduler.rb b/test/async/scheduler.rb index 26bc158b..6a5c6383 100644 --- a/test/async/scheduler.rb +++ b/test/async/scheduler.rb @@ -89,11 +89,13 @@ end it "can interrupt a scheduler from a different thread" do - scheduler = Async::Scheduler.new finished = false sleeping = Thread::Queue.new thread = Thread.new do + scheduler = Async::Scheduler.new + Fiber.set_scheduler(scheduler) + scheduler.run do |task| sleeping.push(true) sleep @@ -105,13 +107,14 @@ finished = true end end - rescue Interrupt - # Ignore. + # rescue Interrupt + # # Ignore. end expect(sleeping.pop).to be == true expect(finished).to be == false + binding.irb thread.raise(Interrupt) expect(sleeping.pop).to be == true From 6be30b3d0e0ed1bd68d6e796d61c6c5d2cb23c0f Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Wed, 3 Jan 2024 14:03:18 +1300 Subject: [PATCH 4/5] Add Ruby v3.1 to coverage workflow. --- .github/workflows/coverage.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/coverage.yaml b/.github/workflows/coverage.yaml index 41f6f584..c18f6f0c 100644 --- a/.github/workflows/coverage.yaml +++ b/.github/workflows/coverage.yaml @@ -20,6 +20,7 @@ jobs: - ubuntu ruby: + - "3.1" - "3.2" - "ruby-head" From 60e33891ad252dff1563a9d9938110b94f26af8c Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Wed, 3 Jan 2024 14:07:49 +1300 Subject: [PATCH 5/5] Remove `binding.irb`. --- test/async/scheduler.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/test/async/scheduler.rb b/test/async/scheduler.rb index 6a5c6383..e1285de1 100644 --- a/test/async/scheduler.rb +++ b/test/async/scheduler.rb @@ -114,7 +114,6 @@ expect(sleeping.pop).to be == true expect(finished).to be == false - binding.irb thread.raise(Interrupt) expect(sleeping.pop).to be == true