EV-Nats
view release on metacpan or search on metacpan
eg/health_checker.pl view on Meta::CPAN
#!/usr/bin/env perl
# Health checker â periodically pings services, reports status
# Run services: perl eg/health_checker.pl service <name>
# Run checker: perl eg/health_checker.pl monitor
use strict;
use warnings;
use EV;
use EV::Nats;
my $mode = shift || 'both';
my $name = shift || "svc$$";
my $nats;
$nats = EV::Nats->new(
host => $ENV{NATS_HOST} // '127.0.0.1',
port => $ENV{NATS_PORT} // 4222,
on_error => sub { warn "nats: @_\n" },
on_connect => sub {
if ($mode eq 'service' || $mode eq 'both') {
# Register health endpoint
$nats->subscribe("health.$name", sub {
my ($subj, $payload, $reply) = @_;
return unless $reply;
# Simulate health: 90% healthy, 10% degraded
my $status = rand() < 0.9 ? 'healthy' : 'degraded';
$nats->publish($reply, "$name:$status:$$:" . int(rand(100)) . "ms");
});
print "service '$name' registered health endpoint\n";
if ($mode eq 'both') {
# Also register a second service for demo
$nats->subscribe("health.db", sub {
my ($subj, $payload, $reply) = @_;
return unless $reply;
$nats->publish($reply, "db:healthy:$$:2ms");
});
$nats->subscribe("health.cache", sub {
my ($subj, $payload, $reply) = @_;
return unless $reply;
$nats->publish($reply, "cache:healthy:$$:0ms");
});
}
}
if ($mode eq 'monitor' || $mode eq 'both') {
my @services = $mode eq 'both'
? ($name, 'db', 'cache')
: split(/,/, $ENV{SERVICES} || $name);
my $checks = 0;
my $t; $t = EV::timer 1, 2, sub {
$checks++;
print "\n--- health check #$checks ---\n";
for my $svc (@services) {
$nats->request("health.$svc", 'ping', sub {
my ($resp, $err) = @_;
if ($err) {
printf " %-10s DOWN (%s)\n", $svc, $err;
} else {
my ($n, $status, $pid, $latency) = split /:/, $resp;
printf " %-10s %-8s pid=%s latency=%s\n", $n, $status, $pid, $latency;
}
}, 1000);
}
if ($checks >= 3) {
undef $t;
my $done; $done = EV::timer 2, 0, sub {
undef $done;
$nats->disconnect;
EV::break;
};
}
};
}
},
);
EV::run;
( run in 1.284 second using v1.01-cache-2.11-cpan-364913b4093 )