App-karr
view release on metacpan or search on metacpan
lib/App/karr/SyncGuard.pm view on Meta::CPAN
# ABSTRACT: Push guard with automatic retry on scope exit
package App::karr::SyncGuard;
our $VERSION = '0.500';
use Moo;
use strict;
use warnings;
use Scalar::Util qw( refaddr weaken );
use App::karr::Git;
# Process-wide registry of armed guards, keyed by refaddr with weakened values
# so a guard that is released normally is not kept alive here. done() and
# DESTROY deregister, flush_armed() drains. In practice a karr process holds at
# most one guard; this is a registry rather than a single slot only because
# nothing guarantees that, and a stale single slot would push the wrong guard.
our %ARMED;
sub BUILD {
my ($self) = @_;
my $key = refaddr $self;
$ARMED{$key} = $self;
weaken $ARMED{$key};
return;
}
has git => (
is => 'ro',
required => 1,
);
has _done => (
is => 'rw',
default => 0,
);
has quiet => (
is => 'ro',
default => 0,
);
has _errors => (
is => 'ro',
default => sub { [] },
);
sub done {
my ($self) = @_;
$self->{_done} = 1;
delete $ARMED{ refaddr $self };
return;
}
sub flush_armed {
my ($class) = @_;
# Drain first: whatever happens below, these guards have been dealt with,
# and a guard freed mid-loop must not leave a dangling registry key.
my @guards = grep { defined } values %ARMED;
%ARMED = ();
return 0 unless $App::karr::Git::WRITES;
my $flushed = 0;
for my $guard (@guards) {
next if $guard->{_done};
$flushed++;
eval { $guard->_insurance_push; 1 }
or warn 'Push insurance failed: ' . ( $@ || 'unknown error' );
# Spent either way: on failure _insurance_push has already warned with
# the "run karr sync" guidance, so DESTROY must not report it again.
( run in 1.282 second using v1.01-cache-2.11-cpan-14f38c9f855 )