Apache-Session-Browseable

 view release on metacpan or  search on metacpan

lib/Apache/Session/Browseable/Store/Patroni.pm  view on Meta::CPAN

        $session->{args}->{DataSource} =
          _buildDataSource( $originalDataSource, $cache->{leader} );
    }

    foreach ( 0 .. 1 ) {
        (
            $self->checkMaster( $session->{args} )
              or warn "Patroni check failed"
        ) if $self->{failure};
        eval {
            $self->{dbh} = DBI->connect(
                $session->{args}->{DataSource},
                $session->{args}->{UserName},
                $session->{args}->{Password},
                { RaiseError => 1, AutoCommit => 0 }
            ) || die $DBI::errstr;
        };
        if ( $@ and !$_ ) {
            $self->{failure} = 1;
        }
        else {
            last;
        }
    }
    die $@ if $@;

    #If we open the connection, we close the connection
    $self->{disconnect} = 1;

    #the programmer has to tell us what commit policy to use
    $self->{commit} = $session->{args}->{Commit} // 1;
}

sub _try {
    my $self = shift;
    my $sub  = shift;
    my $res;

    foreach ( 0 .. 1 ) {
        $res =
          eval { Apache::Session::Store::Postgres->can($sub)->( $self, @_ ) };
        if ( $@ and $@ !~ /Object does not exist/ and !$_ ) {
            $self->{failure} = 1;
            $self->DESTROY;
            delete $self->{"${sub}_sth"};
            delete $self->{dbh};
        }
        else {
            last;
        }
    }
    die $@ if $@;
    return $res;
}

sub insert {
    my $self = shift;
    return $self->_try( 'insert', @_ );
}

sub update {
    my $self = shift;
    return $self->_try( 'update', @_ );
}

sub materialize {
    my $self = shift;
    return $self->_try( 'materialize', @_ );
}

sub remove {
    my $self = shift;
    return $self->_try( 'remove', @_ );
}

sub checkMaster {
    my ( $self, $args ) = @_;
    delete $self->{failure};

    my $originalDataSource =
      $self->{_originalDataSource} || $args->{DataSource};
    my $cache = $patroniCache{$originalDataSource} ||= {};

    # Circuit breaker: avoid hammering Patroni API if it's failing
    my $circuitBreakerDelay = $args->{PatroniCircuitBreakerDelay} || 30;
    if ( $cache->{lastFailure}
        and ( time() - $cache->{lastFailure} ) < $circuitBreakerDelay )
    {
        # Circuit breaker active, try cached leader as fallback
        return $self->_useCachedLeader( $args, $originalDataSource,
            "Circuit breaker active" );
    }

    require JSON;
    require LWP::UserAgent;
    require IO::Socket::SSL;

    # SSL verification: secure by default, can be disabled with PatroniVerifySSL => 0
    my $verify_ssl = $args->{PatroniVerifySSL} // 1;
    my %ssl_opts;
    if ($verify_ssl) {
        %ssl_opts = (
            verify_hostname => 1,
            SSL_verify_mode => &IO::Socket::SSL::SSL_VERIFY_PEER,
            ( $args->{PatroniSSLCAFile} ? ( SSL_ca_file => $args->{PatroniSSLCAFile} ) : () ),
            ( $args->{PatroniSSLCAPath} ? ( SSL_ca_path => $args->{PatroniSSLCAPath} ) : () ),
        );
    }
    else {
        %ssl_opts = (
            verify_hostname => 0,
            SSL_verify_mode => &IO::Socket::SSL::SSL_VERIFY_NONE,
        );
    }

    my $ua = LWP::UserAgent->new(
        env_proxy => 1,
        ssl_opts  => \%ssl_opts,
        timeout   => $args->{PatroniTimeout} || 3,
    );
    my $res;



( run in 4.017 seconds using v1.01-cache-2.11-cpan-5837b0d9d2c )