NAME

Net::Async::Kubernetes::Controller - Minimal controller runtime for Net::Async::Kubernetes

VERSION

version 0.008

SYNOPSIS

use IO::Async::Loop;
use Net::Async::Kubernetes;

my $loop = IO::Async::Loop->new;
my $kube = Net::Async::Kubernetes->new(
    kubeconfig => "$ENV{HOME}/.kube/config",
);
$loop->add($kube);

my $controller = $kube->controller(
    on_reconcile => sub {
        my ($ctx) = @_;

        return $ctx->{controller}->patch_status('Pod', $ctx->{object},
            status => { phase => 'Running' },
        );
    },
);

$controller->watch_resource('Pod', namespace => 'default');
$loop->run;

DESCRIPTION

Net::Async::Kubernetes::Controller is a minimal controller runtime built on top of Net::Async::Kubernetes and its watcher support.

It is intentionally small. The module focuses on the operational pieces most controllers need:

  • watch registration

  • keyed queueing with deduplication

  • serialized reconcile dispatch

  • retry hooks with configurable delay policy

  • status subresource helpers

It does not attempt to provide higher-level controller DSL sugar.

configure

Internal IO::Async::Notifier configuration method.

Accepted parameters:

kube

Existing Net::Async::Kubernetes instance to bind to. The reference is weak, as in Net::Async::Kubernetes::Watcher, so the caller has to keep the client alive for as long as the controller is used.

kubeconfig, context, server, credentials, resource_map, resource_map_from_cluster

Client construction parameters used when kube is not supplied. A client built this way is owned by the controller.

on_reconcile

Required reconcile callback. Receives a hashref with controller, kube, resource, event_type, object, key, and attempt. controller and kube are weak references. Both are valid for the whole reconcile, including anything chained onto the Future it returns, but a context kept past that keeps neither object alive.

on_watch_error

Optional callback for ERROR events from a registered watch, for example a 403 arriving mid-stream. Receives ($error, $ctx), where $error is the raw error hashref the watcher reports and $ctx carries controller, kube, and resource. Error events are not reconcile objects, so they never enter the workqueue. An on_error passed to watch_resource takes precedence for that watch.

retry_delay

Optional retry policy. Accepts a fixed scalar delay, an arrayref of delays, or a coderef receiving ($attempt, $ctx, $error).

kube

Returns the bound Net::Async::Kubernetes client.

on_reconcile

Returns the reconcile callback.

on_watch_error

Returns the watch error callback, if one is configured.

retry_delay

Returns the configured retry delay policy. Defaults to 1.

start

Starts all registered resource watches. Called automatically when the controller is added to an event loop.

stop

Stops registered watches and prevents further queue processing. Each stopped watch is also detached from the client it was registered on, so a watcher handle a caller kept from watch_resource does not survive its controller's stop: it is no longer attached to anything, calling start on it directly drives a notifier with no loop, and the controller's own start builds a fresh watcher for the spec regardless. Do not hold on to a watcher handle past a stop.

Pending work is dropped with them: the workqueue is cleared and any retry timer is cancelled, because a restart re-lists through fresh watches and delivers everything still present again. A key's failure count survives, so a key that was retrying picks up at its next attempt number rather than at attempt 1.

watch_resource

$controller->watch_resource('Pod',
    namespace => 'default',
    key_for   => sub {
        my ($object, $spec) = @_;
        return $object->metadata->name;
    },
);

Registers a watched resource and returns the watcher instance once started. Repeated events for the same reconcile key are coalesced into a single queued entry. A key's entry is dropped once it reconciles cleanly, so the queue does not grow with the number of objects seen; a key that is still queued, dirty or retrying keeps its entry, and with it its attempt count.

get_object

Thin wrapper around $controller->kube->get(...). Returns its Future, resolving to the inflated IO::K8s object.

list_objects

Thin wrapper around $controller->kube->list(...). Returns its Future, resolving to an IO::K8s::List.

patch_status

$controller->patch_status('Pod', 'my-pod',
    namespace => 'default',
    status    => { phase => 'Running' },
)->get;

Patch the /status subresource for an object. Accepts either a class/name pair or an object instance plus a status payload. Returns a Future that resolves to the patched object.

update_status

$controller->update_status($object)->get;

Update the /status subresource for a full object instance. Returns a Future that resolves to the updated object.

SEE ALSO

SUPPORT

Issues

Please report bugs and feature requests on GitHub at https://github.com/Getty/p5-net-async-kubernetes/issues.

IRC

Join #kubernetes on irc.perl.org or message Getty directly.

CONTRIBUTING

Contributions are welcome! Please fork the repository and submit a pull request.

AUTHOR

Torsten Raudssus <torsten@raudssus.de>

COPYRIGHT AND LICENSE

This software is copyright (c) 2026 by Torsten Raudssus <torsten@raudssus.de> https://raudssus.de/.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.