Мое приложение Perl использует ресурсы, которые временами становятся временно недоступными, вызывая исключения с использованием die
. В частности, он обращается к базам данных SQLite, которые используются несколькими потоками и другими приложениями, использующими через DBIx::Class
. Каждый раз, когда возникает такое исключение, операцию следует повторять, пока не истечет время ожидания.
Я предпочитаю лаконичный код, поэтому мне быстро надоело многократно набирать 7 лишних строк для каждой такой операции:
use Time::HiRes 'sleep';
use Carp;
# [...]
for (0..150) {
sleep 0.1 if $_;
eval {
# database access
};
next if $@ =~ /database is locked/;
}
croak $@ if $@;
... поэтому я помещаю их в функцию (для доступа к БД):
sub _retry {
my ( $timeout, $func ) = @_;
for (0..$timeout*10) {
sleep 0.1 if $_;
eval { $func->(); };
next if $@ =~ /database is locked/;
}
croak $@ if $@;
}
который я называю так:
my @thingies;
_retry 15, sub {
$schema->txn_do(
sub {
@thingies = $thingie_rs->search(
{ state => 0, job_id => $job->job_id },
{ rows => $self->{batchsize} } );
if (@thingies) {
for my $thingie (@thingies) {
$thingie->update( { state => 1 } );
}
}
} );
};
Есть ли лучший способ реализовать это? Я изобретаю колесо заново? Есть ли код на CPAN, который мне следует использовать?