App-Config-Chronicle

 view release on metacpan or  search on metacpan

lib/App/Config/Chronicle.pm  view on Meta::CPAN

    if ($app_settings) {
        $data_set->{global}  = Data::Hash::DotNotation->new(data => $app_settings->{global});
        $data_set->{version} = $app_settings->{_rev};
    }

    return;
}

has dynamic_settings_info => (
    is      => 'ro',
    isa     => 'HashRef',
    default => sub { {} },
);

sub _add_dynamic_setting_info {
    my $self       = shift;
    my $path       = shift;
    my $definition = shift;

    $self->dynamic_settings_info           = {} unless ($self->dynamic_settings_info);
    $self->dynamic_settings_info->{global} = {} unless ($self->dynamic_settings_info->{global});

    $self->dynamic_settings_info->{global}->{$path} = {
        type        => $definition->{isa},
        default     => $definition->{default},
        description => $definition->{description}};

    return;
}

=head1 SUBROUTINES/METHODS
######################################################
###### Start new API
######################################################

=head2 local_caching

If local_caching is set to the true then key-value pairs stored in Redis will be cached locally.

Calling update_cache will update the local cache with any changes from Redis.
refresh_interval defines (in seconds) the minimum time between seqequent updates.

Calls to get on this object will only ever access the cache.
Calls to set on this object will immediately update the values in the local cache and Redis.

=cut

has local_caching => (
    isa     => 'Bool',
    is      => 'ro',
    default => 0,
);

=head2 update_cache

Loads latest values from data chronicle into local cache.
Calls to this method are rate-limited by C<refresh_interval>.

=cut

sub update_cache {
    my $self = shift;
    die 'Local caching not enabled' unless $self->local_caching;

    return unless $self->_has_refresh_interval_passed();
    $self->_updated_at(Time::HiRes::time());

    return unless $self->_is_cache_stale();

    my $keys        = [$self->dynamic_keys(), '_global_rev'];
    my @all_entries = $self->_retrieve_objects_from_chron($keys);
    $self->_store_objects_in_cache({map { $keys->[$_] => $all_entries[$_] } (0 .. $#$keys)});

    return 1;
}

sub _has_refresh_interval_passed {
    my $self                   = shift;
    my $now                    = Time::HiRes::time();
    my $prev_update            = $self->_updated_at;
    my $time_since_prev_update = $now - $prev_update;
    return ($time_since_prev_update >= $self->refresh_interval);
}

sub _is_cache_stale {
    my $self      = shift;
    my @rev_cache = $self->_retrieve_objects_from_cache(['_global_rev']);
    my @rev_chron = $self->_retrieve_objects_from_chron(['_global_rev']);
    return !($rev_cache[0] && $rev_chron[0] && $rev_cache[0]->{data} eq $rev_chron[0]->{data});
}

=head2 global_revision

Returns the global revision version of the config chronicle.
This will correspond to the last time any of values were changed.

=cut

sub global_revision {
    my $self = shift;
    return $self->get('_global_rev');
}

=head2 set

Takes a hashref of key->value pairs and atomically sets them in config chronicle

Example:
    set({key1 => 'value1', key2 => 'value2', key3 => 'value3',...});

=cut

sub set {
    my ($self, $pairs) = @_;

    die 'cannot set when $self->chronicle_writer is undefined' unless $self->chronicle_writer;

    my $rev_obj   = Date::Utility->new;
    my $rev_epoch = $rev_obj->{epoch};

    $self->_key_is_dynamic($_) or die "Cannot set with key: $_ | Key must be defined with 'global: 1'" foreach keys %$pairs;



( run in 0.904 second using v1.01-cache-2.11-cpan-56fb94df46f )