Skip to content

Commit

Permalink
Add support for multiple download attempts for assets that need to be…
Browse files Browse the repository at this point in the history
… fetched

This will be disabled by default, and can be enabled with
`$app->asset->store->retries(5)`.
  • Loading branch information
kraih committed Jan 27, 2023
1 parent f44e08f commit 5398671
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 3 deletions.
31 changes: 28 additions & 3 deletions lib/Mojolicious/Plugin/AssetPack/Store.pm
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use Mojo::URL;
use Mojolicious::Types;
use Mojolicious::Plugin::AssetPack::Asset;
use Mojolicious::Plugin::AssetPack::Util qw(diag checksum has_ro DEBUG);
use Time::HiRes qw(sleep);

use constant CACHE_DIR => 'cache';

Expand All @@ -26,6 +27,8 @@ has asset_class => 'Mojolicious::Plugin::AssetPack::Asset';
has default_headers => sub { +{"Cache-Control" => "max-age=31536000"} };
has fallback_headers => sub { +{"Cache-Control" => "max-age=60"} };
has fallback_templates => sub { +{%FALLBACK_TEMPLATES} };
has retry_delay => 3;
has retries => 0;

has _types => sub {
my $t = Mojolicious::Types->new;
Expand Down Expand Up @@ -257,14 +260,22 @@ sub _download {

return $asset if $attrs{url}->host ne 'local' and $asset = $self->_already_downloaded($url);

my $tx = $self->ua->get($url);
my $h = $tx->res->headers;
my $tx;
my $retries = $self->retries;
while (1) {
$tx = $self->ua->get($url);
last unless my $err = $tx->error;

if ($retries-- > 0) {
sleep $self->retry_delay;
next;
}

if (my $err = $tx->error) {
$self->_log->warn("[AssetPack] Unable to download $url: $err->{message}");
return undef;
}

my $h = $tx->res->headers;
my $ct = $h->content_type || '';
if ($ct ne 'text/plain') {
$ct =~ s!;.*$!!;
Expand Down Expand Up @@ -388,6 +399,20 @@ This is currently an EXPERIMENTAL feature.
See L<Mojolicious::Static/paths> for details.
=head2 retry_delay
my $delay = $self->retry_delay;
$self = $self->retry_delay(0.5);
Delay in seconds between download attempts for assets that need to be fetched, defaults to C<3>.
=head2 retries
my $retries = $self->retries;
$self = $self->retries(5);
Number of times asset downloads will be attempted for assets that need to be fetched, defaults to C<0>.
=head2 ua
$ua = $self->ua;
Expand Down
47 changes: 47 additions & 0 deletions t/fetch-retry.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
use lib '.';
use t::Helper;

use Mojo::IOLoop;
use Mojo::Server::Daemon;
use Mojolicious;

my $t = t::Helper->t(pipes => [qw(Css Fetch)]);

my $app = Mojolicious->new;
$app->config->{attempts} = 0;
$app->routes->get(
'/test.css' => sub {
my $c = shift;
return $c->render(data => 'Internal server error', status => 500) if $c->app->config->{attempts}++ <= 2;
$c->render(data => 'body { color: #00f }');
}
);
my $responses = [];
$app->hook(
before_dispatch => sub {
shift->on(finish => sub { push @$responses, shift->res->code });
}
);
my $daemon = Mojo::Server::Daemon->new(listen => ['http://*'], ioloop => $t->app->asset->ua->ioloop, app => $app);
my $port = $daemon->start->ports->[0];

subtest 'Defaults' => sub {
is $t->app->asset->store->retries, 0, 'no retries by default';
is $t->app->asset->store->retry_delay, 3, '3 second retry delay by default';
};

subtest 'Download asset with multiple attempts' => sub {
$t->app->asset->store->retries(3)->retry_delay(0.1);
$t->app->asset->process('app.css' => "http://127.0.0.1:$port/test.css");

$t->get_ok('/')->status_is(200)->content_like(qr{Hello world});
$t->get_ok($t->tx->res->dom->at('link')->{href})->status_is(200)->content_like(qr{body.+color.+00f});
is_deeply $responses, [500, 500, 500, 200], 'right responses';
};

done_testing;

__DATA__
@@ index.html.ep
%= asset 'app.css'
Hello world

0 comments on commit 5398671

Please sign in to comment.