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 )