ruby-core@ruby-lang.org archive (unofficial mirror)
 help / color / mirror / Atom feed
From: "byroot (Jean Boussier)" <noreply@ruby-lang.org>
To: ruby-core@ruby-lang.org
Subject: [ruby-core:108004] [Ruby master Feature#18630] Introduce general `IO#timeout` and `IO#timeout=`for all (non-)blocking operations.
Date: Mon, 21 Mar 2022 15:52:18 +0000 (UTC)	[thread overview]
Message-ID: <redmine.journal-96959.20220321155217.3344@ruby-lang.org> (raw)
In-Reply-To: redmine.issue-18630.20220314024343.3344@ruby-lang.org

Issue #18630 has been updated by byroot (Jean Boussier).


> I'm not sure a timeout per IO instance makes sense,

I think it does for various network clients. See for example [`net-protocol`'s `BufferedIO` class](https://github.com/ruby/net-protocol/blob/088e52609a8768c1e6156fa6c5609bbfadd44320/lib/net/protocol.rb#L115-L302) which backs Net::HTTP and others.

If you want to have a timeout on your network client, you are basically to `read_nonblock / write_nonblock`, so for most line based protocols (such as HTTP but also memcached, redis, etc) you can't use `IO#gets`. This means you need to buffer your reads to find the newline, so now you have the Ruby internal 16KiB IO buffer, plus the `BufferedIO` 16KiB buffer, and you end up calling `String#slice!` repeatedly on that Ruby String which is atrocious for performance.

I recently had to do [the same thing for a new Redis client I'm working on](https://github.com/redis-rb/redis-client/blob/a9b198ec1f312c30f5c5b94be3131c228a950aa8/lib/redis_client/buffered_io.rb), but to save on performance I don't `slice!` the buffer, but keep a numeric `@offset` alongside.

If I understand this proposal correctly, it would allow me to directly call `IO#gets` with the timeout I desire, which would allow me to not have my own buffer and solely rely on the internal one.

That being said, if there was some kind of `IO.timeout(timeout) {}` it would work too. I guess both have their pros and cons.


----------------------------------------
Feature #18630: Introduce general `IO#timeout` and `IO#timeout=`for all (non-)blocking operations.
https://bugs.ruby-lang.org/issues/18630#change-96959

* Author: ioquatix (Samuel Williams)
* Status: Open
* Priority: Normal
----------------------------------------
I would like us to consider introducing a general timeout for all blocking operations. This timeout can be specified per IO instance. It's useful for ensuring programs don't stop responding or spend an unreasonable amount of time waiting for IO operations.

There are effectively two kinds of interfaces that we need to address:

- Those that already have a timeout argument (e.g. `wait_readable`) and we follow the existing semantics.
- Those that don't have a timeout argument or timeout semantics (e.g. `puts`, `gets`), and thus probably need to raise an exception on timeout.

We have three possible kinds of exceptions we could raise:

- `Errno::ETIMEDOUT`
- `Timeout::Error` (from `timeout.rb`)
- Introduce `IO::Timeout` or something similar.

Timeout isn't necessarily an error condition. There are different arguments for whether we should define:

```ruby
class IO::Timeout < Exception
end

# or

class IO::Timeout < StandardError
end
```

I believe the latter (`StandardError`) is more practical but I'm open to either option. I might have more specific arguments later why one is better than the other after testing in a practical system.

There is already a PR to try it out: https://github.com/ruby/ruby/pull/5653



-- 
https://bugs.ruby-lang.org/

  parent reply	other threads:[~2022-03-21 15:52 UTC|newest]

Thread overview: 28+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-03-14  2:43 [ruby-core:107886] [Ruby master Feature#18630] Introduce general `IO#timeout` and `IO#timeout=`for all (non-)blocking operations ioquatix (Samuel Williams)
2022-03-14  4:28 ` [ruby-core:107887] " matz (Yukihiro Matsumoto)
2022-03-14  9:05 ` [ruby-core:107889] " Eregon (Benoit Daloze)
2022-03-14 14:52 ` [ruby-core:107891] " ioquatix (Samuel Williams)
2022-03-17  2:08 ` [ruby-core:107935] " ioquatix (Samuel Williams)
2022-03-17 12:06 ` [ruby-core:107949] " Eregon (Benoit Daloze)
2022-03-17 15:42 ` [ruby-core:107957] " ioquatix (Samuel Williams)
2022-03-21 15:52 ` byroot (Jean Boussier) [this message]
2022-03-21 16:59 ` [ruby-core:108007] " Eregon (Benoit Daloze)
2022-03-21 17:11 ` [ruby-core:108008] " Eregon (Benoit Daloze)
2022-03-21 19:30 ` [ruby-core:108009] " ioquatix (Samuel Williams)
2022-03-28 10:24 ` [ruby-core:108099] " Eregon (Benoit Daloze)
2022-03-29 21:58 ` [ruby-core:108112] " ioquatix (Samuel Williams)
2022-03-31 10:58 ` [ruby-core:108136] " Eregon (Benoit Daloze)
2022-03-31 11:25 ` [ruby-core:108138] " ioquatix (Samuel Williams)
2022-03-31 11:46 ` [ruby-core:108139] " ioquatix (Samuel Williams)
2022-03-31 17:15 ` [ruby-core:108145] " Eregon (Benoit Daloze)
2022-03-31 22:52 ` [ruby-core:108149] " ioquatix (Samuel Williams)
2022-04-21  9:20 ` [ruby-core:108338] " Eregon (Benoit Daloze)
2022-04-21  9:36 ` [ruby-core:108340] " Eregon (Benoit Daloze)
2022-07-20 10:13 ` [ruby-core:109257] [Ruby master Feature#18630] Introduce general `IO#timeout` and `IO#timeout=` for blocking operations ioquatix (Samuel Williams)
2022-07-20 11:48 ` [ruby-core:109262] " ioquatix (Samuel Williams)
2022-09-20 22:49 ` [ruby-core:109967] " ioquatix (Samuel Williams)
2022-09-22 10:22 ` [ruby-core:109996] " ioquatix (Samuel Williams)
2022-09-23  6:35 ` [ruby-core:110032] " ioquatix (Samuel Williams)
2022-10-07  2:28 ` [ruby-core:110222] " ioquatix (Samuel Williams)
2022-10-07  8:32 ` [ruby-core:110225] " matz (Yukihiro Matsumoto)
2022-10-08  7:34 ` [ruby-core:110234] " ioquatix (Samuel Williams)

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.ruby-lang.org/en/community/mailing-lists/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=redmine.journal-96959.20220321155217.3344@ruby-lang.org \
    --to=ruby-core@ruby-lang.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).