# `Kubereq.Watcher`
[🔗](https://github.com/mruoss/kubereq/blob/v0.4.3/lib/kubereq/watcher.ex#L1)

A behaviour module for implementing a Kubernetes watch event handler.

Establishes a watch connection for [efficient detection of changes]
[k8s-watch-concept]. All events are passed to `c:handle_event/3`.

[k8s-watch-concept]: https://kubernetes.io/docs/reference/using-api/api-concepts/#efficient-detection-of-changes

```mermaid
sequenceDiagram
    participant Watcher
    participant K8s as K8s API Server

    Watcher->>K8s: ?watch=true

    loop K8s Detects Changes
      K8s ->> Watcher: {:created, %{"kind" => "Pod"}}
      K8s ->> Watcher: {:modified, %{"kind" => "Pod"}}
      K8s ->> Watcher: {:deleted, %{"kind" => "Pod"}}
    end

```

### Example

When started, `Kubereq.Watcher` establishes a watch connection to the API
Server.

For every watch event, `c:handle_event/3` is then called with the `t:type`,
`object` and `state`.

    defmodule PodEventHandler do
      use Kubereq.Watcher

      require Logger

      def start_link(init_arg) do
        req = Keyword.fetch!(init_arg, :req)
        naemspace = Keyword.get(opts, :namespace)

        Kubereq.Watcher.start_link(__MODULE__, req, namespace, api_version: "v1", kind: "Pod")
      end

      @impl Kubereq.Watcher
      def init(init_arg) do
        initial_state = %{}
        {:ok, initial_state}
      end

      @impl Kubereq.Watcher
      def handle_event(:created, pod, state) do
        Logger.debug("Pod #{pod["metadata"]["name"]} was created.")
        {:noreply, state}
      end

      @impl Kubereq.Watcher
      def handle_event(:modified, pod, state) do
        Logger.debug("Pod #{pod["metadata"]["name"]} was modified.")
        {:noreply, state}
      end

      @impl Kubereq.Watcher
      def handle_event(:deleted, pod, state) do
        Logger.debug("Pod #{pod["metadata"]["name"]} was deleted.")
        {:noreply, state}
      end
    end

# `event_type`

```elixir
@type event_type() :: :created | :modified | :deleted
```

# `handle_event`

```elixir
@callback handle_event(event_type :: event_type(), object :: map(), state :: term()) ::
  {:noreply, new_state}
  | {:noreply, new_state, timeout()}
  | {:stop, reason, new_state}
when new_state: term(), reason: term()
```

Called for every event detected for the resources watched on the Kubernetes
cluster. It is passed the `t:event_type` (one of `:created`, `:modified` or
`:deleted`), the `object` (resource) the event occurred on and the current
  `state`.

# `handle_info`

```elixir
@callback handle_info(msg :: :timeout | term(), state :: term()) ::
  {:noreply, new_state}
  | {:noreply, new_state,
     timeout() | :hibernate | {:continue, continue_arg :: term()}}
  | {:stop, reason, new_state}
when new_state: term(), reason: term()
```

Similar to GenServer's `c:GenServer.handle_info/2`, called for messages sent
to the process.

# `init`

```elixir
@callback init(init_arg :: term()) :: {:ok, state :: any()} | {:stop, reason :: any()}
```

Called when the server is started but before connection is establised.

# `terminate`

```elixir
@callback terminate(reason, state :: term()) :: term()
when reason: :normal | :shutdown | {:shutdown, term()} | term()
```

Similar to GenServer's `c:GenServer.terminate/2`, called then the watcher is
terminated.

# `child_spec`

Returns a specification to start this module under a supervisor.

See `Supervisor`.

# `connect`

Establish a watch connection to the API Server for the given `req`.
If `namespace` is nil, all namespaces are watched.

### Options

All options described in `Kubereq`'s moduledoc plus:

  * `:resource_version` - Optional. Resource version to start watching from.
    Per default, the watcher starts watching from the current
    resource_version.

# `start_link`

Starts a watcher process linked to the current process.

Once the watcher is started, the `c:init/1` function of the given module is
called. After that, the watch connection is established.

### Arguments

`req`, `namespace` and `init_arg` are forwarded to `connect/3`.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
