Beefy Boxes and Bandwidth Generously Provided by pair Networks
Keep It Simple, Stupid
 
PerlMonks  

Re^4: Saving/recovering sub refs in a file

by madscientist (Novice)
on Jun 16, 2010 at 19:42 UTC ( [id://845100]=note: print w/replies, xml ) Need Help??


in reply to Re^3: Saving/recovering sub refs in a file
in thread Saving/recovering sub refs in a file

So for example, the caller runs: my::Error::register('my::Plugins::ThisPlugin::miHandler') but the name of the real sub is myHandler...
Then you should call my::Plugins::ThisPlugin::miHandler. If it throws an error, so be it. If you want to catch the error, use eval BLOCK or whatever module you prefer.

I can't do that, because I can't call their error handler unless I get an error! It would be very incorrect to just call the handler "as a test". Certainly when I do call their handler I absolutely run it in an eval block and catch any undefined reference there.

What I'm trying to do is validate that the sub name is correct and real at registration time, because the input they're giving is only very rarely used (only when a bad error occurs) and so it's quite possible that they could not notice the typo. Yes, of course, all these types of failure scenarious SHOULD be tested, but I prefer to implement defensive programming and fail immediately on the register if the argument I was given is bogus.

Is it possible?

That said, it might make more sense to register the package, then always call a specific method of that package (say ->handle_error()).

Actually I can't do that either: some of these plugins have very complex error conditions and they register multiple error handlers, as the plugin proceeds and makes more changes, and they expect the handlers to be run in the proper order. Further, the same plugin can be called multiple times during the invocation, with different contexts, and this requires different cleanup operations.

There are lots of options here of course, that involve more work by the plugin writers to consolidate all that into one error handler and keep their own internal state (which would need to be cached to disk--remember what I'm trying to implement is a way to "restart" the process after kill -9 or power failure). I can easily come up with these alternatives. However, the method that I have today is powerful and perfect for my needs and for the plugin authors' needs, and I really don't want to rewrite the error handling API and push a lot more work onto them: I want to continue to manage it for them inside my framework, and keep the framework easy to use and robust in the face of misconfiguration.

Thanks!

  • Comment on Re^4: Saving/recovering sub refs in a file

Replies are listed 'Best First'.
Re^5: Saving/recovering sub refs in a file
by ikegami (Patriarch) on Jun 16, 2010 at 20:38 UTC

    some of these plugins have very complex error conditions and they register multiple error handlers

    I don't see the problem. The object could hold all that information without problem, and it's something you can serialize.

      I don't see the problem. The object could hold all that information without problem, and it's something you can serialize.

      Yes, as I said, it can be done. It's just a quality-of-implementation issue. Today, plugin writers just have to write:

      do_a(); my::Error::register(\&undo_a); if ($do_c) { do_c(); my::Error::register(\&undo_c); } do_b(); my::Error::register(\&undo_b);

      and it all just works. The framework handles everything: remembering which recovery handlers have to be run, in which order, and saving this information for catastrophic failure recovery etc. Very tidy.

      If each plugin had a single handler then all the work of remembering which parts of the plugin had been completed and which had not would have to be implemented inside every individual plugin's single error handler, with some package-global variable or variables set to track the current state, then those variables need to be stored somewhere so they can be recovered in the case of catastrophic error, and each plugin needs some kind of method that can be invoked to actually perform the recovery, etc. Instead of one single place, in the framework, implementing that behavior you're now pushing it out so that ALL the plugins have to re-implement it themselves.

      But what I'd really like is to have the best of both worlds. So, is it possible / does anyone know how to take a string name of a sub and determine from that whether that sub actually exists?

      Thanks!

        If each plugin had a single handler then all the work of remembering which parts of the plugin had been completed and which had not would have to be implemented inside every individual plugin's single error handler,

        Where'd you get that from? I didn't suggest removing any calls to register. I suggested you pass an object as argument.

        do_a(); my::Error::register(\&undo_a, ARGS); if ($do_c) { do_c(); my::Error::register(\&undo_c, ARGS); } do_b(); my::Error::register(\&undo_b, ARGS);
        to
        do_a(); register_err_handler(a => ARGS); if ($do_c) { do_c(); register_err_handler(c => ARGS); } do_b(); register_err_handler(b => ARGS); sub register_err_handler { my::Error::register( my::Plugin::ErrorHandler_->new(@_) ); }

        The handler is trivial:

        package my::Plugin::ErrorHandler; sub new { my $class = shift; my $handler = shift; return bless({ handler => $handler, args => [ @_ ] }, $class); } my %dispatch = ( a => \&my::Plugin::undo_a, b => \&my::Plugin::undo_b, c => \&my::Plugin::undo_c, ); sub handle_error { my ($self) = @_; $dispatch{ $self->{handler} }->(@{ $self->{args} }) }

        This gives you a lot of flexibility (including the ability to serialise undo data) without messing with magic.

        That said, given the details that recently came to light, yes, you might as well do

        do_a(); my::Error::register(undo_a => ARGS); if ($do_c) { do_c(); my::Error::register(undo_c => ARGS); } do_b(); my::Error::register(undo_b => ARGS);

        You can always pass an object as one of the args if if custom serialisation is needed.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://845100]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others imbibing at the Monastery: (4)
As of 2024-04-16 06:45 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found