http://qs321.pair.com?node_id=800725

Gangabass has asked for the wisdom of the Perl Monks concerning the following question:

Hi,
i need a way to check if request result was bad (i mean no connection etc.). At this time i check each request with eval:

GET_START: eval { $mech->get( $CONFIG{BASE_URL} ); }; if ($@) { sleep $CONFIG{DELAY}; goto GET_START; }

But this is so ugly. I'm sure i need to subclass WWW::Mechanize but don't know how. Also i need to check for errors on each request (submit_form, get, follow_link etc.). How i can do this?

Replies are listed 'Best First'.
Re: WWW::Mechanize and connection errors
by Limbic~Region (Chancellor) on Oct 12, 2009 at 17:22 UTC
    Gangabass,
    First, I too would probably subclass WWW::Mechanize so that you don't need to keep sprinkling this code all over the place - something like:
    sub my_get { my ($self) = shift(@_); my $result; eval { $result = $self->get(@_); }; # ... if $@ return $result; }
    Second, I would probably avoid the evil goto - something like:
    my $success; while (! $success) { eval { $mech->get(@_); }; if (! $@) { $success = 1; } else { sleep $CONFIG{DELAY}; } }
    Third, I would consider that you have introduced an infinite loop and would probably re-write it to include a $CONFIG{MAX_RETRY}. The code above is not intended to be copy/paste but give you an idea of how it might be accomplished - you will need to fill in the blanks.

    If your real problem is that you have never sub-classed before at all then you should probably make that clear. After reading your question again, I am not sure if you just don't know how to subclass in general or how to write the wrapper to do what you want.

    Cheers - L~R

Re: WWW::Mechanize and connection errors
by saberworks (Curate) on Oct 12, 2009 at 16:50 UTC
    Other than the goto, what's ugly about it? That's a pretty standard way to test for failure. Mechanize is based on LWP, which provides methods to check for errors (including connection errors). Mechanize has wrapper methods for these as well -- check success(). I don't think that suite of modules ever dies on connection error. You can just:
    my $response = $mech->get($url); if($response->is_success()) { # do your stuff } else { # grab the status? warn "Unable to connect: " . $response->status_line(); }
Re: WWW::Mechanize and connection errors
by almut (Canon) on Oct 12, 2009 at 19:33 UTC
    I'm sure i need to subclass WWW::Mechanize but don't know how.

    Subclassing could look something like this:

    package MyMech; use WWW::Mechanize; our @ISA = "WWW::Mechanize"; sub _wrapped { my $self = shift; my $method = "SUPER::".shift; my $result; RETRY: for (1..3) { eval { $result = $self->$method(@_); }; if ($@) { warn gmtime(time).": $@"; $result = undef; # just in case sleep 5; } else { last RETRY; } } return $result; } sub get { shift->_wrapped('get', @_) } sub put { shift->_wrapped('put', @_) } # ...

    and then in the main script:

    #!/usr/bin/perl use MyMech; my $mech = MyMech->new(autocheck => 1); my $resp = $mech->get("http://localhost:9999/foo"); # ... __END__ Mon Oct 12 19:32:48 2009: Error GETing http://localhost:9999/foo: Can' +t connect to localhost:9999 (connect: Connection refused) at ./800725 +.pl line 7 Mon Oct 12 19:32:53 2009: Error GETing http://localhost:9999/foo: Can' +t connect to localhost:9999 (connect: Connection refused) at ./800725 +.pl line 7 Mon Oct 12 19:32:58 2009: Error GETing http://localhost:9999/foo: Can' +t connect to localhost:9999 (connect: Connection refused) at ./800725 +.pl line 7

    (note that in the example I use a generic wrapper doing the error checking and retries, so you don't have to write the same boilerplate code for every subclassed method that's meant to be handled similarly.  You of course don't have to do it that way...  in which case the call to the respective superclass method would simply be $self->SUPER::get(@_), etc. instead)

Re: WWW::Mechanize and connection errors
by Anonymous Monk on Oct 17, 2009 at 20:17 UTC
    Please revisit perlsyn :)
    until ( $mech->success() ) { eval { $mech->get( $CONFIG{BASE_URL} ); 1; } or sleep $CONFIG{DELAY}; }