Concepts
How the KubeMQ KEDA external scaler works — the external-scaler gRPC protocol, the Waiting metric, and external vs external-push trigger types.
This page explains the model behind the KubeMQ KEDA external scaler: the gRPC protocol KEDA
speaks to it, the single metric it exposes, and the two trigger types that determine how KEDA
drives it. For the metric's underlying meaning — the queue Waiting count — see the
Queues concept; the scaler does not redefine it.
The external-scaler protocol
KEDA scales workloads from external signals through scalers: small gRPC services that
implement KEDA's ExternalScaler interface. KEDA does not know anything about KubeMQ — it only
knows how to call these four RPCs and act on the answers. The KubeMQ scaler implements all four,
translating each call into a ListQueuesChannels read against the broker.
| RPC | What KEDA asks | What the scaler does |
|---|---|---|
IsActive | "Should this workload be running at all?" | Reads the live Waiting count, returns true when Waiting > activationTargetWaiting. |
StreamIsActive | (push mode) "Stream me active-status changes." | Sends the active flag once, then re-evaluates on a fixed 5s ticker and pushes each update. |
GetMetricSpec | "What is the target value for your metric?" | Returns targetWaiting as the target for kubemq-queue-waiting. No broker call. |
GetMetrics | "What is the current value?" | Reads the live Waiting count and returns it as the metric value. |
Every RPC parses the ScaledObject trigger metadata first and returns gRPC InvalidArgument
on a bad spec before touching KubeMQ, so a misconfigured trigger fails fast without loading
the broker.
The scaler is a service, not a client library. You do not write Go against it — you write a
KEDA ScaledObject (YAML) whose external trigger metadata configures the scaler. The full
metadata schema lives in the ScaledObject metadata reference.
The single metric: kubemq-queue-waiting
The scaler exposes exactly one metric. Its value is the queue channel's Outgoing.Waiting
count, obtained by calling client.ListQueuesChannels(queueName) and matching the channel whose
Name equals queueName.
| Metric | Source | Used by |
|---|---|---|
kubemq-queue-waiting | The channel's Outgoing.Waiting count from ListQueuesChannels. | GetMetricSpec (target = targetWaiting) and GetMetrics (current value). |
KEDA divides the current Waiting count by targetWaiting and rounds up to compute the desired
replica count, then clamps it to your minReplicaCount / maxReplicaCount bounds. This is the
standard KEDA / HPA math — the scaler only supplies the numerator (the live backlog) and the
target.
If the broker responds successfully but the named channel is absent from the returned list,
the scaler reports Waiting = 0 (an empty queue is a legitimate signal, scaling the workload to
its minimum). On any KubeMQ failure it instead returns a gRPC error — see
Never-fake-zero below.
Trigger types: external vs external-push
KEDA supports two external trigger types against the same scaler. They differ only in how KEDA drives the scaler, not in what the scaler measures.
| Type | Mode | How KEDA drives it | Best for |
|---|---|---|---|
external | Poll (default) | Calls IsActive and GetMetrics every pollingInterval seconds. | Steady workloads with minReplicaCount >= 1. |
external-push | Push | Opens a long-lived StreamIsActive stream; the scaler pushes active-status updates on its own 5s ticker, independent of pollingInterval. | Fast scale-from-zero. |
In poll mode the soonest KEDA can notice the first message is the next pollingInterval tick. In
push mode the scaler holds the stream open and pushes an active signal as soon as it detects
waiting work — so a workload at zero replicas wakes up sooner without forcing a tiny
pollingInterval across the whole metric pipeline. Even in push mode, KEDA still reads the metric
via GetMetrics on the pollingInterval cadence to do the replica math.
The activation gate
Computing a replica count and deciding whether the workload should be active at all are two
separate decisions. Activation is governed by activationTargetWaiting: the scaler reports active
only when Waiting > activationTargetWaiting (strictly greater-than).
activationTargetWaitingdefaults to0, so the very first waiting message (Waiting == 1) activates the workload.- Setting it to
"1"requiresWaiting >= 2before waking up — useful to keep a single stray message from paying the cost of a cold start.
The activation gate only matters when you allow the workload to reach zero (minReplicaCount: 0).
With a minReplicaCount of 1 or more, the floor is held by minReplicaCount regardless of
activation. See Scale to Zero for the end-to-end
flow.
Never-fake-zero
A queue that is genuinely empty and a broker that is unreachable both could look like "zero work" — but they demand opposite responses. Scaling a healthy workload to zero on a transient outage would strand the queue with no consumer.
The scaler resolves this by never returning OK with a fabricated Waiting = 0 on a KubeMQ
failure. It maps each KubeMQ error class to a gRPC status code and returns it, so KEDA can apply
its fallback replica strategy instead of scaling down. A genuine empty queue (channel present,
Waiting = 0, or channel absent from the list) is the only path that yields 0. The full mapping
lives in the error-codes reference.
Next steps
Was this page helpful?