加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

perl – 异常后重试操作:请批评我的代码

发布时间:2020-12-16 06:20:04 所属栏目:大数据 来源:网络整理
导读:我的Perl应用程序使用暂时不可用的资源,导致使用die的异常.最值得注意的是,它访问由多个线程共享的SQLite数据库以及通过DBIx :: Class使用的其他应用程序.每当发生此类异常时,都应重试该操作,直到达到超时. 我更喜欢简洁的代码,因此我很快就厌倦了 为每个这
我的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 $@;

…所以我将它们放入(特定于DB访问)功能:

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上的代码吗?

解决方法

我可能倾向于写这样的重试:

sub _retry {
    my ( $retrys,$func ) = @_;
    attempt: {
      my $result;

      # if it works,return the result
      return $result if eval { $result = $func->(); 1 };

      # nah,it failed,if failure reason is not a lock,croak
      croak $@ unless $@ =~ /database is locked/;

      # if we have 0 remaining retrys,stop trying.
      last attempt if $retrys < 1;

      # sleep for 0.1 seconds,and then try again.
      sleep 0.1;
      $retrys--;
      redo attempt;
    }

    croak "Attempts Exceeded $@";
}

它与现有代码的工作方式不同,但有一些优点.

>我摆脱了* 10的东西,就像另一张海报,我无法辨别其目的.
>此函数能够将$func()所做的值返回给其调用者.
>在语义上,代码更类似于你正在做的事情,至少对我迷茫的思想而言.
> _retry 0,sub {};仍将执行一次,但永远不会重试,不像你现在的版本,永远不会执行sub.

更多建议(但稍微不那么理性)的抽象:

sub do_update {
  my %params = @_;
  my @result;

  $params{schema}->txn_do( sub {
      @result = $params{rs}->search( @{ $params{search} } );
      return unless (@result);
      for my $result_item (@result) {
        $result_item->update( @{ $params{update} } );
      }
  } );
  return @result;
}

my $data = _retry 15,sub {
  do_update(
    schema => $schema,rs     => $thingy_rs,search => [ { state => 0,{ rows => $self->{batchsize} } ],update => [ { state => 1 } ],);
};

这些也可能是您代码的便利补充. (未经测试)

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读