[open-ils-commits] r7737 - trunk/Open-ILS/src/perlmods/OpenILS/WWW
svn at svn.open-ils.org
svn at svn.open-ils.org
Wed Aug 29 12:08:33 EDT 2007
Author: erickson
Date: 2007-08-29 12:02:40 -0400 (Wed, 29 Aug 2007)
New Revision: 7737
Modified:
trunk/Open-ILS/src/perlmods/OpenILS/WWW/AddedContent.pm
Log:
Gave the added content module the ability to do book jacket lookups in addition to its current duties
in addition, book jackets are cached in memcache, which means Apache disk/mem caching won't be necessary
also added in an error checking layer where if X consecutive errors occur, all added content lookups,
except for locally cached images, are disabled until the retry timeout has passed. These new
settings go into the added_content section of the opensrf.xml config file.
new settings:
jacket_url
retry_timeout
All that's left is to add the automatic disable capabilities to the other lookups
Modified: trunk/Open-ILS/src/perlmods/OpenILS/WWW/AddedContent.pm
===================================================================
--- trunk/Open-ILS/src/perlmods/OpenILS/WWW/AddedContent.pm 2007-08-29 16:02:27 UTC (rev 7736)
+++ trunk/Open-ILS/src/perlmods/OpenILS/WWW/AddedContent.pm 2007-08-29 16:02:40 UTC (rev 7737)
@@ -17,100 +17,203 @@
use OpenSRF::Utils::Cache;
use OpenSRF::System;
use OpenSRF::Utils::Logger qw/$logger/;
-use XML::LibXML;
+use LWP::UserAgent;
+use MIME::Base64;
+
# set the bootstrap config when this module is loaded
my $bs_config;
my $handler;
sub import {
- my $self = shift;
- $bs_config = shift;
+ my $self = shift;
+ $bs_config = shift;
}
-my $net_timeout;
-my $cache;
+my $net_timeout; # max seconds to wait for a response from the added content vendor
+my $cache; # memcache handle
+my $max_errors; # max consecutive lookup failures before added content is temporarily disabled
+my $error_countdown; # current consecutive errors countdown
+my $jacket_url; # URL for fetching jacket images
+
+# number of seconds to wait before next lookup
+# is attempted after lookups have been disabled
+my $error_retry_timeout;
+my $init = 0; # has the child init been run?
+
+
sub child_init {
- OpenSRF::System->bootstrap_client( config_file => $bs_config );
+ OpenSRF::System->bootstrap_client( config_file => $bs_config );
- my $sclient = OpenSRF::Utils::SettingsClient->new();
- my $ac_data = $sclient->config_value("added_content");
+ my $sclient = OpenSRF::Utils::SettingsClient->new();
+ my $ac_data = $sclient->config_value("added_content");
return unless $ac_data;
$cache = OpenSRF::Utils::Cache->new;
- my $ac_handler = $ac_data->{module};
- $net_timeout = $ac_data->{timeout} || 3;
+ $net_timeout = $ac_data->{timeout} || 1;
+ $error_countdown = $max_errors = $ac_data->{max_errors} || 10;
+ $jacket_url = $ac_data->{jacket_url};
+ $error_retry_timeout = $ac_data->{retry_timeout} || 600;
+
+ $init = 1;
- return unless $ac_handler;
+ my $ac_handler = $ac_data->{module};
- $logger->debug("Attempting to load Added Content handler: $ac_handler");
+ if($ac_handler) {
+ $logger->debug("Attempting to load Added Content handler: $ac_handler");
+
+ eval "use $ac_handler";
+
+ if($@) {
+ $logger->error("Unable to load Added Content handler [$ac_handler]: $@");
+ return;
+ }
+
+ $handler = $ac_handler->new($ac_data);
+ $logger->debug("added content loaded handler: $handler");
+ }
+}
- eval "use $ac_handler";
- if($@) {
- $logger->error("Unable to load Added Content handler [$ac_handler]: $@");
- return;
- }
+sub handler {
- $handler = $ac_handler->new($ac_data);
- $logger->debug("added content loaded handler: $handler");
+ my $r = shift;
+ my $cgi = CGI->new;
+ my $path = $r->path_info;
+
+ my( undef, $data, $format, $key ) = split(/\//, $r->path_info);
+ return Apache2::Const::NOT_FOUND unless $data and $format and $key;
+
+ child_init() unless $init;
+ return Apache2::Const::NOT_FOUND unless $init;
+
+ return fetch_jacket($format, $key) if $data eq 'jacket';
+ return Apache2::Const::NOT_FOUND unless lookups_enabled();
+
+ my $err;
+ my $success;
+ my $method = "${data}_${format}";
+
+ try {
+ $success = $handler->$method($key);
+ } catch Error with {
+ my $err = shift;
+ $logger->error("added content handler failed: $method($key) => $err");
+ };
+
+ return Apache2::Const::NOT_FOUND if $err or !$success;
+ return Apache2::Const::OK;
}
-sub handler {
- my $r = shift;
- my $cgi = CGI->new;
- my $path = $r->path_info;
+# generic GET call
+sub get_url {
+ my( $self, $url ) = @_;
+ $logger->info("added content getting [timeout=$net_timeout] URL = $url");
+ my $agent = LWP::UserAgent->new(timeout => $net_timeout);
+ my $res = $agent->get($url);
+ die "added content request failed: " . $res->status_line ."\n" unless $res->is_success;
+ return $res->content;
+}
- child_init() unless $handler; # why isn't apache doing this for us?
- return Apache2::Const::NOT_FOUND unless $handler;
-
- # if this memcache key is set, added content lookups are disabled
- if( $cache->get_cache('ac.no_lookup') ) {
+sub lookups_enabled {
+ if( $cache->get_cache('ac.no_lookup') ) {
$logger->info("added content lookup disabled");
- return Apache2::Const::NOT_FOUND;
+ return undef;
}
+ return 1;
+}
+sub disable_lookups {
+ $cache->put_cache('ac.no_lookup', 1, $error_retry_timeout);
+}
- my( undef, $data, $format, $key ) = split(/\//, $r->path_info);
+sub fetch_jacket {
+ my($size, $isbn) = @_;
+ return Apache2::Const::NOT_FOUND unless $jacket_url and $size and $isbn;
- my $err;
- my $success;
- my $method = "${data}_${format}";
+ if($size eq 'small') {
- try {
- $success = $handler->$method($key);
- } catch Error with {
- my $err = shift;
- $logger->error("added content handler failed: $method($key) => $err");
- };
+ # try to serve small images from the cache first
+ my $img_data = $cache->get_cache("ac.$size.$isbn");
- return Apache2::Const::NOT_FOUND if $err or !$success;
- return Apache2::Const::OK;
-}
+ if($img_data) {
+ $logger->debug("serving jacket $isbn from cache...");
+ my $c_type = $img_data->{content_type};
+ my $img = decode_base64($img_data->{img});
-# generic GET call
-sub get_url {
- my( $self, $url ) = @_;
- $logger->info("added content getting [timeout=$net_timeout] URL = $url");
- my $agent = LWP::UserAgent->new(timeout => $net_timeout);
- my $res = $agent->get($url);
- die "added content request failed: " . $res->status_line ."\n" unless $res->is_success;
- return $res->content;
+ print "Content-type: $c_type\n\n";
+
+ binmode STDOUT;
+ print $img;
+ return Apache2::Const::OK;
+ }
+ }
+
+ if(!lookups_enabled()) {
+ $error_countdown = $max_errors; # reset the counter
+ return Apache2::Const::NOT_FOUND;
+ }
+
+ (my $url = $jacket_url) =~ s/\${isbn}/$isbn/ig;
+
+ $logger->debug("added content getting jacket with timeout=$net_timeout and URL = $url");
+
+ my $res;
+ my $err;
+
+ try {
+ my $agent = LWP::UserAgent->new(timeout => $net_timeout);
+ $res = $agent->get($url);
+ } catch Error with {
+ $err = shift;
+ $logger->error("added content lookup died with $err");
+ };
+
+ if( $err or $res->code == 500 ) {
+ $logger->warn("added content jacket fetch failed (retries remaining = $error_countdown) " .
+ (($res) ? $res->status_line : "$err"));
+ $error_countdown--;
+ if($error_countdown < 1) {
+ $logger->warn("added content error count exhausted. Disabling lookups for $error_retry_timeout seconds");
+ disable_lookups();
+ }
+ return Apache2::Const::NOT_FOUND;
+ }
+
+ return Apache2::Const::NOT_FOUND unless $res->code == 200;
+
+ # ignore old errors after a successful lookup
+ $error_countdown = $max_errors if $error_countdown < $max_errors;
+
+ my $c_type = $res->header('Content-type');
+ my $binary_img = $res->content;
+ print "Content-type: $c_type\n\n";
+
+ binmode STDOUT;
+ print $binary_img;
+
+ $cache->put_cache(
+ "ac.$size.$isbn", {
+ content_type => $c_type,
+ img => encode_base64($binary_img,'')
+ }
+ ) if $size eq 'small';
+
+ return Apache2::Const::OK;
}
-
1;
More information about the open-ils-commits
mailing list