Project

General

Profile

Feature #17470

Introduce non-blocking `Timeout.timeout`

Added by ioquatix (Samuel Williams) 2 months ago. Updated 23 days ago.

Status:
Open
Priority:
Normal
Assignee:
-
Target version:
-
[ruby-core:101704]

Description

In this bug report, user complained that Timeout.timeout does not work correctly with scheduler: https://github.com/socketry/async-io/issues/43

We should introduce non-blocking timeout.

I propose the following:

rb_fiber_scheduler_with_timeout(VALUE scheduler, VALUE timeout, VALUE block)

We can directly modify Timeout.timeout to invoke this hook.


Related issues

Related to Ruby master - Feature #17363: TimeoutsAssignedko1 (Koichi Sasada)Actions

Updated by Eregon (Benoit Daloze) 2 months ago

How would that work, what would be a sample implementation of the hook?
Timeout.timeout must be able to interrupt non-IO operations as well.

Updated by ioquatix (Samuel Williams) 2 months ago

Timeout.timeout must be able to interrupt non-IO operations as well.

Actually, that's not necessarily true, even for the current implementation, see getaddrinfo for example.

Updated by jsc (Justin Collins) 2 months ago

It appears that Timeout.timeout does not work when a Fiber scheduler is set, regardless of the implementation, even when Fibers are not explicitly in use.

Simple example using the sample scheduler:

require 'timeout'
require 'fiber'
require_relative 'scheduler'

scheduler = Scheduler.new
Fiber.set_scheduler scheduler

Timeout.timeout 1 do
  puts "hello"
end

This code will print "hello" then hang.

Updated by Eregon (Benoit Daloze) 2 months ago

ioquatix (Samuel Williams) wrote in #note-2:

Actually, that's not necessarily true, even for the current implementation, see getaddrinfo for example.

You're completely evading my question :p
Could you answer it please?

That's one of the very rare cases, maybe even the only case in core methods that cannot be interrupted by Thread#raise.

Is the idea to simply give up on interrupting anything that's not handled by the scheduler if there is a Fiber.scheduler, or something better?
That seems too incompatible to me.
I think a new API to interrupt only scheduler things might make more sense (related to #17363).

#5

Updated by Eregon (Benoit Daloze) 2 months ago

#6

Updated by jeremyevans0 (Jeremy Evans) 25 days ago

  • Backport deleted (2.5: UNKNOWN, 2.6: UNKNOWN, 2.7: UNKNOWN)
  • Tracker changed from Bug to Feature

Updated by ioquatix (Samuel Williams) 23 days ago

Eregon (Benoit Daloze) without preemptive scheduling it won't be possible. There are other cases where the GVL is not released, e.g. the sqlite3 gem. In the case of the scheduler, Timeout.timeout is completely broken, so this is an improvement any way you cut it.

Updated by ioquatix (Samuel Williams) 23 days ago

jsc (Justin Collins) I tried your example but it seems to work fine?

  MESSAGE = "Hello World"

  def test_timeout_on_main_fiber
    message = nil

    thread = Thread.new do
      scheduler = Scheduler.new
      Fiber.set_scheduler scheduler

      Timeout.timeout(1) do
        message = MESSAGE
      end
    end

    thread.join

    assert_equal MESSAGE, message
  end

Also available in: Atom PDF