# KEDA (/integrations/keda)



The **KubeMQ KEDA external scaler** brings Kubernetes-native autoscaling to KubeMQ
queue consumers. It is a standalone gRPC service that reads the live `Waiting` message
count from a KubeMQ queue channel and exposes it to [KEDA](https://keda.sh) as a single
metric, so a `ScaledObject` can scale queue-consuming workloads — GPU inference workers,
batch processors, task consumers — up and down (and all the way to zero) on real backlog
rather than CPU or memory.

## What it is [#what-it-is]

KEDA is the Kubernetes Event-Driven Autoscaler. It scales workloads from external signals
through *scalers* — small gRPC services that implement KEDA's `ExternalScaler` interface.
The KubeMQ scaler is one such service: it answers KEDA's `IsActive` / `GetMetrics` calls by
querying the broker's `ListQueuesChannels` API and reporting the channel's `Outgoing.Waiting`
count.

Unlike the framework adapters in this section, KEDA is **not a messaging client your app
embeds** — it is an autoscaler that runs alongside your consumers. Your consumers connect to
KubeMQ with the [native gRPC SDK](/deploy) on port `50000` as usual; the scaler
observes the same queues over that API and tells KEDA how many replicas to run. The metric it
exposes is queue depth, so the underlying concept is [Queues](/learn/queues) — the scaler reads
the same `Waiting` count you would see when introspecting a queue channel.

## Why KEDA + KubeMQ [#why-keda--kubemq]

* **Queue-depth-driven autoscaling** — scale on the live `Waiting` count of a [queue](/learn/queues), not on CPU or memory.
* **Scale-to-zero** — drop a deployment to zero replicas when its queue is empty and scale back up the moment work arrives.
* **Never-fake-zero** — KubeMQ errors map to gRPC status codes so KEDA applies its `fallback` strategy on a broker outage instead of scaling a healthy workload to zero.
* **Push or poll** — `external` (poll) and `external-push` (long-lived stream) trigger types, the latter for faster scale-from-zero detection.
* **Lightweight** — a single Go service requesting just `50m` CPU and `64Mi` memory, hardened with a non-root, read-only-root-filesystem `securityContext`.

## Architecture [#architecture]

The scaler is a standalone gRPC `ExternalScaler` server (default port `9090`). The KEDA
operator calls it to read queue depth; the scaler in turn dials the KubeMQ broker's gRPC API
(`50000`), calls `ListQueuesChannels`, and reports the `Waiting` count so KEDA can scale the
target deployment.

<Mermaid
  chart="`
graph LR
KEDA[&#x22;KEDA Operator&#x22;]
SCALER{{&#x22;kubemq-keda-scaler<br/>ExternalScaler :9090&#x22;}}
BROKER[&#x22;KubeMQ Broker<br/>gRPC :50000&#x22;]
DEPLOY[&#x22;Target Deployment&#x22;]

KEDA -- &#x22;gRPC: IsActive · GetMetrics&#x22; --> SCALER
SCALER -- &#x22;ListQueuesChannels<br/>Waiting count&#x22; --> BROKER
KEDA -- &#x22;scale up / down&#x22; --> DEPLOY

class KEDA external
class SCALER aiway
class BROKER broker
class DEPLOY client
`"
/>

*The KEDA operator reads queue depth from the scaler, which polls the KubeMQ broker and drives the target deployment's replica count.*

## The metric and the RPCs [#the-metric-and-the-rpcs]

The scaler exposes exactly one metric, `kubemq-queue-waiting`, whose value is the queue
channel's `Outgoing.Waiting` count. It implements the four RPCs of KEDA's `ExternalScaler`
service:

| RPC              | Purpose                                                                                               |
| ---------------- | ----------------------------------------------------------------------------------------------------- |
| `IsActive`       | Returns `true` when `Waiting > activationTargetWaiting` — the scale-from-zero gate.                   |
| `StreamIsActive` | Server-streaming. Pushes active status immediately, then re-polls every `5s`. Drives `external-push`. |
| `GetMetricSpec`  | Returns the target value for `kubemq-queue-waiting`, set from `targetWaiting`.                        |
| `GetMetrics`     | Returns the current `Waiting` count as the metric value.                                              |

KEDA supports two trigger types against the same scaler — `external` (poll-based, default) and
`external-push` (a long-lived `StreamIsActive` stream for faster scale-from-zero). See
[Concepts](/integrations/keda/concepts) for the full model.

## Prerequisites [#prerequisites]

* **Kubernetes 1.27+** — required for the native gRPC liveness/readiness probes the scaler uses.
* **KEDA 2.10+** — installed in the cluster.
* **A KubeMQ broker** — reachable in-cluster on its gRPC port `50000` at the address you pass in `kubemqAddress`.

## Supported runtime [#supported-runtime]

The scaler is a standalone Go service, not a language SDK you embed — your consumers can be written in any language and connect to the broker over native gRPC as usual.

| Requirement                         | Version                                       |
| ----------------------------------- | --------------------------------------------- |
| KEDA                                | 2.10+                                         |
| Kubernetes                          | 1.27+                                         |
| Scaler image                        | `kubemq/kubemq-keda-scaler:1.0.0`             |
| `github.com/kubemq-io/kubemq-go/v2` | v2.0.3                                        |
| Go (to build from source)           | 1.25+                                         |
| KubeMQ broker                       | gRPC on `:50000` (always on — no enable flag) |

## A ScaledObject at a glance [#a-scaledobject-at-a-glance]

A `ScaledObject` targets your consumer `Deployment` and points an `external` trigger at both the
scaler Service and your broker:

```yaml title="scaled-object-basic.yaml"
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: kubemq-queue-scaler
spec:
  scaleTargetRef:
    name: my-queue-consumer
  pollingInterval: 15
  cooldownPeriod: 60
  minReplicaCount: 1
  maxReplicaCount: 10
  triggers:
    - type: external
      metadata:
        scalerAddress: kubemq-keda-scaler.default.svc.cluster.local:9090
        kubemqAddress: kubemq.default.svc.cluster.local:50000
        queueName: my-queue
        targetWaiting: "10"
```

## Explore [#explore]

<Cards>
  <Card title="Getting Started" href="/integrations/keda/tutorials/getting-started" description="Install the scaler with Helm, create your first ScaledObject, and watch a consumer scale on queue depth." />

  <Card title="Concepts" href="/integrations/keda/concepts" description="The external-scaler protocol, the Waiting metric, and external vs external-push trigger types." />

  <Card title="Guides" href="/integrations/keda/how-to/autoscale-queue-consumer" description="Autoscale a queue consumer, enable scale-to-zero, and connect over TLS with an auth token." />

  <Card title="Reference" href="/integrations/keda/reference/scaled-object-metadata" description="ScaledObject metadata, environment variables, the gRPC RPCs, and the error-to-gRPC mapping." />
</Cards>

New to integrations? See [what an integration is](/integrations#what-an-integration-is)
for the mental model, then the [Queues](/learn/queues) concept and the
[Getting Started guide](/deploy) for the core SDK your consumers use. The scaler
observes queues over native gRPC on port `50000` — it is not a [connector](/connectors).
