KubeMQ
IntegrationsKEDAConcepts

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.

RPCWhat KEDA asksWhat 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.

MetricSourceUsed by
kubemq-queue-waitingThe 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.

TypeModeHow KEDA drives itBest for
externalPoll (default)Calls IsActive and GetMetrics every pollingInterval seconds.Steady workloads with minReplicaCount >= 1.
external-pushPushOpens 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).

  • activationTargetWaiting defaults to 0, so the very first waiting message (Waiting == 1) activates the workload.
  • Setting it to "1" requires Waiting >= 2 before 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?

On this page