fREWdiculous!
4 Mar
I have some extremely basic code using AnyEvent but I recently found out that I was doing it wrong. That is, the entire reason I am using an event loop is to catch errors, log them, and keep going. That’s one of the great benefits that Catalyst gives me; I override one thing and I get universal error logging. The problem is that AnyEvent specifically does not handle this use case.
I have a working solution, but as I am planning on rewriting our services in evented code this prohibition makes me really worried. The problem is that you can’t just know your code won’t die. Exceptions happen and as a developer of a language that’s not Java or C# I don’t know where they come from. My current solution is ok, but I don’t think it’s really viable long term. Here’s my current code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | #!/usr/bin/env perl use strict; use warnings; use AnyEvent; use Try::Tiny; sub event { print "looped\n"; die "lol" if rand() < .5; } sub NEVER_DIE { my $code = shift; return sub { try \&$code, catch { warn $_ } # <-- this should be logging, you get the idea } } my $cv = AE::cv; my $w = AE::timer 0, 1, NEVER_DIE(\&event); $cv->recv; |
This works for simple cases, but if I chose to go down this route in the long term I’d have to wrap every single code ref in NEVER_DIE, which is pretty lame.
I looked at POE as it may support my use case better but as far as I can tell it’s support is WORSE. Here’s what I came up with:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | #!/usr/bin/perl use strict; use warnings; use POE; use Try::Tiny; sub handler_start { my ($kernel, $heap, $session) = @_[KERNEL, HEAP, SESSION]; $kernel->yield('event'); } sub NEVER_DIE { my $code = shift; return sub { try \&$code, catch { warn $_ } # <-- this should be logging, you get the idea } } sub event { print "looped\n"; die "lol" if rand() < .5; $_[KERNEL]->delay_add('event', 1); } POE::Session->create( inline_states => { _start => \&handler_start, event => NEVER_DIE(\&event), _stop => sub{}, } ); POE::Kernel->run(); exit; |
So I still have to use NEVER_DIE, so that’s a lose, and worse, if event dies before the call to delay_add we end anyway. Sure, I could put delay_add at the beginning of event, but that brings me to another thing that really bothers me about the “POE Way” (my own terminology, I may just not be getting it), for my AnyEvent code I can add a bunch of things and they don’t have to know about each other. The loop handles calling the events. With POE it seems like I have to manually tell it “call this, now call this.” That seems to defeat the entire purpose! What am I missing here?
If anyone knows an event loop I should consider (MUST RUN WELL ON WINDOWS) or maybe some setting in POE and some kind of POE timer thing, or some way of safely overriding how AE calls it’s events, please, comment and let me know.
3 Responses for "Perl Event Loop"
Why don’t you just call AnyEvent::Debug::wrap as the FAQ you point to suggests?
From the description there it seems that it does exactly what you want, and wraps everything in an eval for you, and even provides some nice debugging output.
But as you linked to it, you probably have your own reasons, but I’m left wondering what they might be.
@tom: that’s certainly a sensible response. Mostly I just think that if a framework is explicitly meant NOT to do something, using debug tools to make that work is not a good way to solve your problem. Furthermore, if the debugging output is merely printing to stderr (which I expect it is) that’s not really helpful, since this is a daemon that I want to have errors logged to a database. For what it’s worth I found an OK way to do this with POE, thanks to Rocco Caputo, but sadly POE is fairly low level, so it makes me a little bummed, but so it goes. I’ll post again with my findings.
I agree on the “don’t abuse debugging infrastructure” stance, but it is definitely a starting point for this.
I just checked the code though, and it appears that it uses anyevent::log internally, which it states can be used to do anything you want with the log message. (but I didn’t check that!)
http://cpansearch.perl.org/src/MLEHMANN/AnyEvent-6.14/lib/AnyEvent/Debug.pm
Thanks for the blog.
Leave a reply