EV-Etcd

 view release on metacpan or  search on metacpan

eg/watch_config_tree.pl  view on Meta::CPAN

#!/usr/bin/env perl
#
# Example: Mirror an etcd prefix into a local nested hash using Data::Path::XS
# (optional CPAN module — install separately to run this example).
#
# etcd keys like /myapp/db/host -> "localhost" become:
#   $config = { db => { host => "localhost" } }
#
use strict;
use warnings;
use lib 'blib/lib', 'blib/arch';
use EV;
use EV::Etcd;
use Data::Path::XS qw(path_get path_set path_delete);
use Data::Dumper;

my $prefix = "/myapp/";
my %config;

my $client = EV::Etcd->new(endpoints => ['127.0.0.1:2379']);

# Seed some data
print "=== Seeding config ===\n";
$client->txn(
    compare => [],
    success => [
        { put => { key => "${prefix}db/host",    value => "localhost" } },
        { put => { key => "${prefix}db/port",    value => "5432" } },
        { put => { key => "${prefix}cache/host", value => "redis.local" } },
        { put => { key => "${prefix}cache/ttl",  value => "3600" } },
    ],
    failure => [],
    sub {
        my ($resp, $err) = @_;
        die "Seed failed: $err->{message}" if $err;
        EV::break;
    }
);
my $t0 = EV::timer(5, 0, sub { die "timeout" });
EV::run;

# Load initial snapshot into tree
$client->get($prefix, { prefix => 1 }, sub {
    my ($resp, $err) = @_;
    die "Load failed: $err->{message}" if $err;

    for my $kv (@{$resp->{kvs} || []}) {
        my $path = substr($kv->{key}, length($prefix) - 1); # keep leading /
        path_set(\%config, $path, $kv->{value});
    }

    print "Initial config tree:\n", Dumper(\%config);

    # Watch from next revision — no gap between load and watch
    my $rev = $resp->{header}{revision} + 1;

    $client->watch($prefix, { prefix => 1, start_revision => $rev }, sub {
        my ($resp, $err) = @_;
        if ($err) {
            print "Watch error: $err->{message}\n";
            return;
        }
        for my $ev (@{$resp->{events} || []}) {
            my $path = substr($ev->{kv}{key}, length($prefix) - 1);
            if (($ev->{type} // 'PUT') eq 'DELETE') {
                path_delete(\%config, $path);
                print "DELETE $path\n";
            } else {
                path_set(\%config, $path, $ev->{kv}{value});
                print "PUT    $path = $ev->{kv}{value}\n";
            }
        }
        print "Config tree:\n", Dumper(\%config);
    });

    EV::break;
});
my $t1 = EV::timer(5, 0, sub { die "timeout" });
EV::run;



( run in 0.605 second using v1.01-cache-2.11-cpan-524268b4103 )