NAME

Try::ALRM - Try/catch-style semantics for handling timeouts using CORE::alarm

SYNOPSIS

Try::ALRM provides a structured, readable way to use alarm and $SIG{ALRM} without scattering signal handlers, local variables, and cleanup logic throughout your code.

The primary entry point is retry, which retries a block multiple times when an alarm fires:

use Try::ALRM;

retry {
  my ($attempts) = @_;
  printf "Attempt %d/%d...\n", $attempts, tries;
  sleep 5;
}
ALRM {
  my ($attempts) = @_;
  print "\tTIMED OUT";
  if ($attempts < tries) {
    print " - retrying...\n";
  } else {
    print " - giving up...\n";
  }
}
finally {
  my ($attempts, $successful) = @_;
  my $limit   = tries;
  my $timeout = timeout;

  if ($successful) {
    print "Succeeded after $attempts attempts\n";
  } else {
    print "Failed after $limit attempts\n";
  }
}
timeout => 3,
tries   => 4;

Single-attempt usage

try_once is a reduced form of retry equivalent to tries => 1. It exists because “retry” can read awkwardly when no retry is intended.

try_once {
  my ($attempts) = @_;
  print "Doing something that might timeout...\n";
  sleep 6;
}
ALRM {
  print "Wake up!\n";
}
finally {
  my ($attempts, $successful) = @_;
  print $successful ? "Completed\n" : "Timed out\n";
}
timeout => 1;

IMPROVEMENT OVER RAW alarm

Traditional alarm usage

local $SIG{ALRM} = sub {
    print "Wake up!\n";
};

alarm 1;
print "Doing something that might timeout...\n";
sleep 6;
alarm 0;

This works, but quickly becomes hard to reason about when retries, cleanup, or shared state are involved.

Equivalent Try::ALRM version

try_once {
  print "Doing something that might timeout...\n";
  sleep 6;
}
ALRM {
  print "Wake up!\n";
}
timeout => 1;

What improved:

  • Signal handling is localized and declarative

  • alarm 0 cleanup is automatic

  • Retry and finalization hooks are explicit

  • Control flow reads top-to-bottom

DESCRIPTION

Try::ALRM provides try/catch-like semantics around alarm. Because ALRM signals are localized and expected, they can be treated as a form of exception without using die.

Internally, this module uses Perl prototypes to coerce lexical blocks into CODE references, in the same spirit as Try::Tiny. The result is a structured syntax:

retry { ... }
ALRM  { ... }
finally { ... }

This structure improves readability without changing the underlying mechanics of alarm or $SIG{ALRM}.

EXPORTS

This module exports six keywords.

NOTE: Either try_once or retry is required. They are mutually exclusive.

try_once BLOCK

Runs BLOCK once with an alarm set to the current timeout value.

If an alarm fires, the ALRM block is executed (if provided), followed by finally. The alarm is always cleared automatically.

retry BLOCK

Runs BLOCK up to tries times. Each attempt receives the current attempt count via @_.

Retries stop when either:

  • The block completes without an alarm

  • The retry limit is reached

ALRM BLOCK

Optional handler executed when an alarm fires. Receives the current attempt count.

finally BLOCK

Optional block executed unconditionally at the end.

Receives:

my ($attempts, $successful) = @_;

timeout INT

Getter/setter for the default timeout in seconds.

May also be supplied as a trailing modifier:

try_once { ... } timeout => 2;

tries INT

Getter/setter for retry limit.

May also be supplied as a trailing modifier:

retry { ... } tries => 5;

PACKAGE ENVIRONMENT

The following package variables are exposed:

  • $Try::ALRM::TIMEOUT

  • $Try::ALRM::TRIES

They may be set globally, lexically (via setters), or temporarily via trailing modifiers.

TRAILING MODIFIERS

Trailing modifiers are written as key/value pairs after the final block:

retry {
  ...
}
ALRM {
  ...
}
finally {
  ...
} timeout => 5, tries => 10;

This mirrors Perl constructs like map and grep.

WHY USE THIS MODULE?

Try::ALRM does not replace alarm. It makes alarm-based logic:

  • Easier to read

  • Safer to modify

  • Less error-prone

  • More expressive

BUGS

Almost certainly.

This module was motivated both by curiosity about Perl prototypes and by the practical question of whether ALRM could be treated as a localized exception.

Mileage may vary. Please report issues.

PERL ADVENT 2022

| \__ `\O/  `--  {}    \}    {/    {}    \}    {/    {}    \} 
\    \_(~)/_..___/=____/=____/=____/=____/=____/=____/=____/=*
 \=======/    //\\  >\/> || \>  //\\  >\/> || \>  //\\  >\/> 
----`---`---  `` `` ```` `` ``  `` `` ```` `` ``  ````  ````

ACKNOWLEDGEMENTS

"This module is dedicated to the least of you amongst us, the defenseless unborn, and to all of those who have died suddenly."

AUTHOR

Brett Estrade (OODLER) <oodler@cpan.org>

COPYRIGHT AND LICENSE

Copyright (C) 2022-Present by Brett Estrade

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.