Skip to content

Commit

Permalink
Add an example of handling POE sig('DIE') from Reflex.
Browse files Browse the repository at this point in the history
This is adapted from fREW Schmidt's test program posted to
irc.perl.org #poe.  He asked whether a timer could handle exceptions
from its own callbacks, and this is an attempt to implement it in
terms of POE's SIGDIE exception handling.
  • Loading branch information
rcaputo committed Mar 4, 2012
1 parent 65eb070 commit 5a5072e
Showing 1 changed file with 91 additions and 0 deletions.
91 changes: 91 additions & 0 deletions eg/eg-45-sigdie.pl
@@ -0,0 +1,91 @@
#!/usr/bin/perl

# Build a new kind of Interval timer with a POE exception handler
# built into it. Jams the Reflex role for an interval timer together
# with the role for a signal handler.
#
# The goal is to have a convenient interval timer which can safely
# expose exceptions thrown from its callbacks. It's based on
# http://blog.afoolishmanifesto.com/archives/1682 and a question from
# fREW Schmidt on irc.perl.org #poe.
#
# Unfortunately lower-level event dispatchers (i.e., POE and the event
# loops it uses) don't know enough about higher-level consumers like
# Reflex to map exceptions back to specific objects. The
# RobustInterval catches die() globally via $SIG{__DIE__}. It doesn't
# know which object died, so it reports unhandled exceptions from
# anywhere.
#
# We need to think more carefully about what it means to throw
# exceptions from Reflex event handler callbacks. What extensible,
# sane things can be done with those exceptions?

{

package RobustInterval;

use Moose;
extends 'Reflex::Base';
use Reflex::Callbacks qw(make_emitter);

# Incorporate an interval timer.

has interval => (isa => 'Num', is => 'rw');
has auto_repeat => (isa => 'Bool', is => 'rw', default => 1);
has auto_start => (isa => 'Bool', is => 'ro', default => 1);

with 'Reflex::Role::Interval' => {
att_auto_repeat => "auto_repeat",
att_auto_start => "auto_start",
att_interval => "interval",
cb_tick => make_emitter(on_tick => "tick"),
method_repeat => "repeat_interval",
method_start => "start_interval",
method_stop => "stop_interval",
};

# Incorporate a signal watcher.

has signal => (is => 'ro', isa => 'Str', default => 'DIE');
has active => (is => 'ro', isa => 'Bool', default => 1);

with 'Reflex::Role::SigCatcher' => {
att_signal => 'signal',
att_active => 'active',
cb_signal => make_emitter(on_die => "die"),
method_start => 'start_signal',
method_stop => 'stop_signal',
method_pause => 'pause_signal',
method_resume => 'resume_signal',
};
}

### Main.

use warnings;
use strict;

use Reflex;

sub event {
print "looped\n";
die "lol" if rand() < .5;
}

sub stumble {
my ($self) = @_;

warn "$self callback died... stumbling on";

$self->resume_signal(); # Resume watching for signals.
$self->repeat_interval(); # Continue the timer.
}

my $ct = RobustInterval->new(
interval => 1,
auto_repeat => 1,
on_tick => \&event,
on_die => \&stumble,
);

Reflex->run_all();

0 comments on commit 5a5072e

Please sign in to comment.