IO::So...Timeout(3pm)

πŸ“¦
version 0.32 Β· 7 versions
, in debian bookworm, debian trixie, ubuntu noble, ubuntu resolute, ubuntu stonking

πŸ’– IO::Socket::Timeout β€” the manual, but make it cute πŸ’–

okay so bestie, you know how IO::Socket is that Perl module that lets you open sockets? yeah. this is the glow-up. it's the IO::Socket::Timeout page from the Perl docs (perl v5.36.0, and the page itself is dated 2022-11-19, iykyk) and we're gonna go through every single thing on it together. grab a snack. πŸ“


✨ NAME ✨

IO::Socket::Timeout β€” it's IO::Socket, but with read/write timeout. that's it, that's the whole vibe. πŸ’…


🌸 VERSION 🌸

version 0.32. periodt.


πŸŽ€ SYNOPSIS πŸŽ€

here's the whole thing in action, no cap:

use IO::Socket::Timeout;

# creates a standard IO::Socket::INET object, with a connection timeout
my $socket = IO::Socket::INET->new( Timeout => 2 );
# enable read and write timeouts on the socket
IO::Socket::Timeout->enable_timeouts_on($socket);
# setup the timeouts
$socket->read_timeout(0.5);
$socket->write_timeout(0.5);

# When using the socket:
use Errno qw(ETIMEDOUT EWOULDBLOCK);
print $socket "some request";
my $response = <$socket>;
if (! $response && ( 0+$! == ETIMEDOUT || 0+$! == EWOULDBLOCK )) {
  die "timeout reading on the socket";
}

so like β€” make the socket, turn the timeouts ON, set them, then actually use it and check your errors. the 0+$! thing is you forcing that errno into a number, because vibes. 🌈


πŸ¦‹ DESCRIPTION πŸ¦‹

okay so here's the tea. IO::Socket does let you set a timeout, bestie β€” but it's only for the connection. not for reading. not for writing. just the connect. that's it. 🫠

this module is the fix. it gives you a way to set a timeout on read / write operations on an IO::Socket instance β€” or honestly any IO::Socket::* module out there, like IO::Socket::INET. literally any of them. slay. πŸ‘‘


πŸ‘‘ CLASS METHOD πŸ‘‘

πŸ’« enable_timeouts_on πŸ’«

IO::Socket::Timeout->enable_timeouts_on($socket);

you hand it a socket, and it hands it right back to you β€” but now read and write timeouts are switched on for it. ✨ note that you still gotta use read_timeout and write_timeout on it afterwards to actually, y'know, set them. enabling β‰  setting, bestie, don't get it twisted.

it returns the socket, so you can chain this method with other methods like the main character you are. πŸ’…

and if the argument is undef? it just returns an empty list. no drama, no crash, we love a graceful exit. πŸ™ˆ


🌟 METHODS 🌟

heads up: all of these get called on a socket that has already been passed to enable_timeouts_on(). you can't skip that step, bestie, it's the prerequisite. πŸŽ€

🧚 read_timeout

my $current_timeout = $socket->read_timeout();
$socket->read_timeout($new_timeout);

get or set the read timeout value, for a socket created with this module. that's the whole thing. πŸ’–

🧚 write_timeout

my $current_timeout = $socket->write_timeout();
$socket->write_timeout($new_timeout);

get or set the write timeout value, for a socket created with this module. twin of the one above, but for writing. 🌸

🧚 disable_timeout

$socket->disable_timeout;

turns the read and write timeouts off for a socket created with this module. bye timeouts. πŸ’€

🧚 enable_timeout

$socket->enable_timeout;

re-enables the read and write timeouts for a socket created with this module. she's back. πŸ”₯

🧚 timeout_enabled

my $is_timeout_enabled = $socket->timeout_enabled();
$socket->timeout_enabled(0);

get or set the fact of whether a socket has timeouts enabled. like, the boolean truth of it. ⭐


😭 WHEN TIMEOUT IS HIT 😭

when a timeout hits β€” read or write β€” the function that was trying to do its little thing will return undef or an empty string, and $! gets set to ETIMEOUT or EWOULDBLOCK. you should test for both. no picking favorites. πŸ™…

and yeah, you can import ETIMEOUT and EWOULDBLOCK by using POSIX:

use Errno qw(ETIMEDOUT EWOULDBLOCK);
bestie this is important: if you only check one of the two errno values, you're gonna have a bad time. check both. always. 🚨

πŸ” IF YOU NEED TO RETRY πŸ”

wanna build a try / wait / retry situation? my honest recommendation is to use a third-party module for it, like Action::Retry. something like this:

my $socket;

my $action = Action::Retry->new(
  attempt_code => sub {
      # (re-)create the socket if needed
      if (! $socket) {
        $socket = IO::Socket->new(...);
        IO::Socket::Timeout->enable_timeouts_on($socket);
        $socket->read_timeout(0.5);
      }
      # send the request, read the answer
      $socket->print($_[0]);
      defined(my $answer = $socket->getline)
        or $socket = undef, die $!;
      $answer;
  },
  on_failure_code => sub { die 'aborting, to many retries' },
);

my $reply = $action->run('GET mykey');

see how it re-creates the socket if it needs to, sends the request, reads the answer, and bails with die $! if it got nothing back? that's the pattern. 🫢


🌈 IMPORT options 🌈

you can pass a list of socket module names when you use this module β€” that way, internally, the composed classes that are needed get created and loaded at compile time. like:

use IO::Socket::Timeout qw(IO::Socket::INET);

efficient. we love her. ✨


πŸ“ ENVIRONMENT VARIABLE πŸ“

πŸ’œ PERL_IO_SOCKET_TIMEOUT_FORCE_SELECT πŸ’œ

okay so this module implements timeouts using one of two strategies:

  1. if it can (aka if the operating system is linux, freebsd or mac), it uses setsockopt() to set the read / write timeouts.
  2. otherwise, it uses select() before performing socket operations.

and if you wanna force the select() route? set PERL_IO_SOCKET_TIMEOUT_FORCE_SELECT to a true value at compile time β€” typically in a BEGIN block. iykyk. πŸ’…


πŸŽ€ SEE ALSO πŸŽ€

go read these too, bestie, they're all part of the family:

  • Action::Retry
  • IO::Select
  • PerlIO::via::Timeout
  • Time::Out

🫢 THANKS 🫢

shoutout to Vincent Pitt, Christian Hansen and Toby Inkster for all the various help and the useful remarks. absolute icons, every one of them. 🌟


πŸ‘‘ AUTHOR πŸ‘‘

Damien "dams" Krotkine. the moment. the legend. πŸ’…


this software is copyright (c) 2013 by Damien "dams" Krotkine.

it's free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. πŸͺ


and that's the whole page, bestie!! πŸ’–βœ¨ every flag, every method, every errno, every env var, all of it. this was documented for perl v5.36.0, page dated 2022-11-19, and honestly? iconic of it. go forth and set your timeouts. πŸŽ€πŸ¦‹πŸŒΈπŸ‘‘

πŸ“¦ where this page comes from