Fabric Capacity Events en Real-Time Hub: Monitorización en tiempo real de tu capacidad
Autor
Kilian Baccaro Salinas
Categoría
Monitoring
Tiempo de lectura
07 min de lectura
Fecha de publicación
23 jul, 2026
¿Por qué monitorizar la capacidad en tiempo real?
En Microsoft Fabric, toda la computación consume Capacity Units (CUs). Cuando el consumo supera el presupuesto disponible, el sistema activa mecanismos de throttling escalonados que degradan primero las operaciones interactivas y, si el overage persiste, también las operaciones en background.
El problema histórico era la latencia del diagnóstico: el Fabric Capacity Metrics app ofrece visibilidad detallada, pero con un retraso de varias horas y sin capacidad de reacción automática. Si tu capacidad entra en throttling a las 2:00 AM, lo sabrás cuando ya pasó.
Fabric Capacity Events en Real-Time Hub resuelve exactamente este problema. Expone el estado y la utilización de tu capacidad como un stream de eventos que puedes consumir con Eventstream, almacenar en un Eventhouse o conectar directamente a Fabric Activator para disparar alertas automáticas.
Arquitectura y flujo de datos

El acceso al stream se gestiona desde Real-Time Hub → Fabric Events → Fabric Capacity Overview Events.

Desde ahí tienes dos acciones directas:
-
Create Eventstream — para ingestar y enrutar los eventos a un Eventhouse u otros destinos.
-
Set Alert — para conectar Fabric Activator y disparar acciones ante cambios de estado.

Tipos de eventos
Microsoft.Fabric.Capacity.Summary
Se emite cada 30 segundos mientras la capacidad está activa. Contiene el consumo agregado de CUs en esa ventana temporal, desglosado por tipo de operación y workload. Es el evento más importante para análisis de tendencias y detección de overages.
Nota: Cuando la capacidad está pausada, no se emiten eventos Summary. Al reanudarla, todo el uso suavizado (smoothed) acumulado se vuelca en la primera ventana disponible, lo que puede generar picos de utilización aparentes de hasta el 288.000% si la capacidad estaba muy ocupada al pausarse.
Microsoft.Fabric.Capacity.State
Se emite únicamente cuando cambia el estado de la capacidad. No es periódico. Puede haber días o semanas sin ningún evento de este tipo si la capacidad permanece estable. Los estados posibles incluyen:
| Estado / Razón de cambio | Descripción |
|---|---|
Active / ManuallyResumed | Capacidad activa y sin throttling |
InteractiveDelay | Throttling leve: operaciones interactivas ralentizadas |
InteractiveRejection | Throttling grave: operaciones interactivas rechazadas |
BackgroundRejection | Throttling extremo: operaciones background también rechazadas |
Paused | Capacidad pausada manualmente o por políticas de autoscale |
Patrón importante: Una tabla de estados vacía en Eventhouse no es un error. Si tu capacidad ha estado activa sin throttling desde que empezaste a recopilar datos, simplemente no habrá eventos State que registrar. Interpreta la ausencia de eventos como
NotOverloaded.
Implementación paso a paso
Paso 1 — Crear el Eventstream y suscribir la capacidad
Desde Real-Time Hub → + Add source, se selecciona Fabric events → Capacity overview events como origen. En la configuración de la conexión hay tres decisiones clave:
-
Event type(s): seleccionar los dos tipos —
Microsoft.Fabric.Capacity.SummaryyMicrosoft.Fabric.Capacity.State. Ambos son necesarios para tener visibilidad completa de utilización y cambios de estado. -
Event scope:
By capacity— permite suscribirse a una capacidad concreta en lugar de a todo el tenant. -
Capacity: seleccionar la capacidad a monitorizar (en el ejemplo,
msfabricf2).

Con esta configuración el Eventstream queda suscrito al feed de eventos de la capacidad seleccionada. El sistema emitirá eventos Summary cada 30 segundos y eventos State en cada cambio de estado, que el Eventstream recibirá por su CustomEndpoint interno.
Paso 2 — Configurar el destino: Eventhouse
Una vez definido el origen, se añade un destino de tipo Eventhouse con modo de ingesta DirectIngestion. Se crea una tabla nueva llamada CapacityEventsRaw en la KQL Database de destino, con el mapping JSON que corresponde al envelope CloudEvents.
El resultado es un flujo activo de tres nodos:

Cuando ambos nodos muestran estado Active, la ingesta está en marcha. Los primeros eventos Summary empiezan a llegar en menos de un minuto.
Paso 3 — Verificar la ingesta en CapacityEventsRaw
En el Eventhouse, la tabla CapacityEventsRaw actúa como buffer de eventos brutos. Su retención puede configurarse corta (1 hora es suficiente) porque no es el almacén final — su única función es recibir los eventos y dejar que las update policies los parseen hacia las tablas tipadas.
El Data Activity Tracker del Eventhouse confirma la ingesta en tiempo real: cada pulso corresponde a la llegada de un lote de eventos Summary de la ventana de 30 segundos.

Una query rápida para verificar que todo llega correctamente:
CapacityEventsRaw
| take 10

Estructura de los eventos
Los campos más relevantes del evento Summary para el día a día son:
-
baseCapacityUnitsycapacityUnitMs— con estos dos valores se puede calcular:-
El % de utilización real de la ventana:
utilizacion_pct = (capacityUnitMs / (baseCapacityUnits × 1000 × 30)) × 100 -
Cálculo del presupuesto de CUs
El presupuesto disponible para una ventana de 30 segundos es:
presupuesto_CUms = baseCapacityUnits × 1.000 × 30Por ejemplo, para una capacidad F64 (
baseCapacityUnits = 64):presupuesto_CUms = 64 × 1.000 × 30 = 1.920.000 CU-ms por ventana
-
-
interactiveDelayThresholdPercentage,interactiveRejectionThresholdPercentageybackgroundRejectionThresholdPercentage— los tres umbrales de throttling, expresados como % de utilización proyectada a 10 min, 1 hora y 24 horas respectivamente. Cuando superan el 100%, el throttling está activo o es inminente. -
overageTotalCapacityUnitMs— el carry-forward acumulado, es decir, la “deuda de CUs” que el sistema tiene pendiente de quemar. Un valor alto aquí significa que el throttling persistirá aunque el consumo baje. -
capacityUnitUtilizationBreakdown— objeto que desglosa el consumo por workload (SparkCore,AS,DMS,Kusto,ES…), muy útil para identificar qué servicio está presionando la capacidad. Para el evento State, los campos clave soncapacityState,stateChangeReasonytransitionTime, que juntos dan el cuándo y el porqué de cada cambio.

Paso 4 — Tablas finales con UpdatePolicies
Tanto para los eventos de tipo Summary o State, los datos más relevantes se encuentran en la columna data de tipo dynamic (JSON). En base a esto, se van a crear 3 tablas para almacenar los datos ya estructurados sin necesidad de ejecutar una consulta KQL cada vez que queramos obtener estos datos.
De esta forma, a medida que se reciben los datos por el eventstream se almacenan en estas tablas de manera automática con la query que hayamos definido para cada una de ellas, eso es lo que hace una Update Policy.
CapacityState
En esta tabla almacenaremos los datos de tipo State de manera que podamos ver tener el capacityId, capacitySky, estado de la capacidad…
.create-or-alter function with (folder = "UpdatePolicyFunctions", skipvalidation = "true") parse_CapacityEventsState() {
CapacityEventsRaw
| where ["type"] == "Microsoft.Fabric.Capacity.State"
| extend
tenantId = toguid(""),
capacityId=toguid(data.capacityId),
capacityName=tostring(data.capacityName),
capacitySku=tostring(data.capacitySku),
capacityRegion = "",
transitionTime=todatetime(data.transitionTime),
capacityState=tostring(data.capacityState),
stateChangeReason=tostring(data.stateChangeReason)
| project
id,
specversion,
source,
['time'],
subject,
dataschemaversion,
type,
tenantId,
capacityId,
capacityName,
capacitySku,
capacityRegion,
transitionTime,
capacityState,
stateChangeReason
}
Para crear la tabla con el resultado de esta consulta ejecutamos:
.set CapacityState <|
parse_CapacityEventsState()
Por último, asignamos la función como Update Policy para que se ejecute a medida que se reciben datos:
.alter table CapacityState policy update
```[{
"IsEnabled": true,
"Source": "CapacityEventsRaw",
"Query": "parse_CapacityEventsState",
"IsTransactional": true,
"PropagateIngestionProperties": false
}]```

CapacitySummary
En esta tabla almacenaremos los datos de tipo Summary de manera que podamos ver tener las ventanas de 30seg y las CUs utilizadas, valores de throttling, smoothing…
.create-or-alter function with (folder = "UpdatePolicyFunctions", skipvalidation = "true") parse_CapacityEventsSummary() {
CapacityEventsRaw
| where ["type"] == "Microsoft.Fabric.Capacity.Summary"
| extend
tenantId=toguid(data.tenantId),
capacityId=toguid(data.capacityId),
capacityName=tostring(data.capacityName),
capacitySku=tostring(data.capacitySku),
capacityRegion=tostring(data.capacityRegion),
windowEndTime=todatetime(data.windowEndTime),
windowStartTime=todatetime(data.windowStartTime),
baseCapacityUnits=tolong(data.baseCapacityUnits),
capacityUnitMs=toreal(data.capacityUnitMs),
interactiveDelayThresholdPercentage=toreal(data.interactiveDelayThresholdPercentage),
interactiveRejectionThresholdPercentage=toreal(data.interactiveRejectionThresholdPercentage),
backgroundRejectionThresholdPercentage=toreal(data.backgroundRejectionThresholdPercentage),
overageTotalCapacityUnitMs=toreal(data.overageTotalCapacityUnitMs),
overageAddCapacityUnitMs=toreal(data.overageAddCapacityUnitMs),
overageBurndownCapacityUnitMs=toreal(data.overageBurndownCapacityUnitMs),
utilizationBackground=toreal(data.utilizationBackground),
utilizationInteractive=toreal(data.utilizationInteractive),
utilizationBackgroundPreview=toreal(data.utilizationBackgroundPreview),
utilizationInteractivePreview=toreal(data.utilizationInteractivePreview),
processedOverageCapacityUnitsMs=toreal(data.processedOverageCapacityUnitsMs),
capacityUnitUtilizationBreakdown=data.capacityUnitUtilizationBreakdown,
overageBillingLimitCapacityUnitsMs=toreal(data.overageBillingLimitCapacityUnitsMs)
| extend
timepointCapacityUnits = baseCapacityUnits * 30,
capacityUnitSecond=capacityUnitMs / 1000.0
| project
id,
specversion,
source,
['time'],
subject,
dataschemaversion,
type,
tenantId,
capacityId,
capacityName,
capacitySku,
capacityRegion,
windowStartTime,
windowEndTime,
baseCapacityUnits,
timepointCapacityUnits,
capacityUnitMs,
capacityUnitSecond,
interactiveDelayThresholdPercentage,
interactiveRejectionThresholdPercentage,
backgroundRejectionThresholdPercentage,
overageTotalCapacityUnitMs,
overageAddCapacityUnitMs,
overageBurndownCapacityUnitMs,
utilizationBackground,
utilizationInteractive,
utilizationBackgroundPreview,
utilizationInteractivePreview,
processedOverageCapacityUnitsMs,
capacityUnitUtilizationBreakdown,
overageBillingLimitCapacityUnitsMs
}
Para crear la tabla con el resultado de esta consulta ejecutamos:
.set CapacitySummary <|
parse_CapacityEventsSummary()
Por último, asignamos la función como Update Policy para que se ejecute a medida que se reciben datos:
.alter table CapacitySummary policy update
```[{
"IsEnabled": true,
"Source": "CapacityEventsRaw",
"Query": "parse_CapacityEventsSummary",
"IsTransactional": true,
"PropagateIngestionProperties": false
}]```

CapacityWorkloadSummary
En esta tabla almacenaremos los datos de tipo Summary de manera que podamos ver tener las ventanas de 30seg y el tipo de carga de trabajo (Lakehouse, EventStream…)
junto con las CUs consumidas en background e interativas y así poder detectar rápidamente cual es el que se está llevando más capacidad.
.create-or-alter function with (folder = "UpdatePolicyFunctions", skipvalidation = "true") parse_CapacityEventsWorkloadSummary() {
CapacityEventsRaw
| where ["type"] == "Microsoft.Fabric.Capacity.Summary"
| where isnotempty(data.capacityUnitUtilizationBreakdown)
| extend
tenantId=toguid(data.tenantId),
capacityId=toguid(data.capacityId),
capacityName=tostring(data.capacityName),
capacitySku=tostring(data.capacitySku),
capacityRegion=tostring(data.capacityRegion),
windowEndTime=todatetime(data.windowEndTime),
windowStartTime=todatetime(data.windowStartTime),
baseCapacityUnits=tolong(data.baseCapacityUnits),
cuBreakdown=data.capacityUnitUtilizationBreakdown
| mv-expand cuBreakdown
| project
id,
specversion,
source,
['time'],
subject,
dataschemaversion,
type,
tenantId,
capacityId,
capacityName,
capacitySku,
capacityRegion,
windowStartTime,
windowEndTime,
baseCapacityUnits,
workloadKind = tostring(cuBreakdown.WorkloadKind),
interactiveCU= iff(isempty(cuBreakdown.Utilization.Interactive), 0.0, todouble(cuBreakdown.Utilization.Interactive)),
backgroundCU = iff(isempty(cuBreakdown.Utilization.Background), 0.0, todouble(cuBreakdown.Utilization.Background)),
interactivePreviewCU = iff(isempty(cuBreakdown.UtilizationPreview.Interactive), 0.0, todouble(cuBreakdown.UtilizationPreview.Interactive)),
backgroundPreviewCU = iff(isempty(cuBreakdown.UtilizationPreview.Background), 0.0, todouble(cuBreakdown.UtilizationPreview.Background))
}
Para crear la tabla con el resultado de esta consulta ejecutamos:
.set CapacityWorkloadSummary <|
parse_CapacityEventsWorkloadSummary()
Por último, asignamos la función como Update Policy para que se ejecute a medida que se reciben datos:
.alter table CapacityWorkloadSummary policy update
```[{
"IsEnabled": true,
"Source": "CapacityEventsRaw",
"Query": "parse_CapacityEventsWorkloadSummary",
"IsTransactional": true,
"PropagateIngestionProperties": false
}]```

Configurar alertas con Fabric Activator
Desde la página de detalle de Fabric Capacity Overview Events en Real-Time Hub, el botón Set Alert permite crear reglas en Fabric Activator sin necesidad de escribir código.

Desde el eventstream también podemos crear alertas sobre determinados eventos a la vez que almacenamos los datos en Eventhouse

En este ejemplo, se filtran los eventos de tipo Microsoft.Fabric.Capacity.Summary y se obtienen los campos relevantes de la columna data

Con esto se puede crear una alerta que se dispare cuando el porcentaje de utilización de la capacidad para operaciones de background supere un umbral determinado, por ejemplo, el 85% de la capacidad total.

Otros casos de uso recomendados:
-
Alerta de throttling inminente:
interactiveDelayThresholdPercentage > 80→ notificación por email/Teams antes de que empiece el throttling real. -
Cambio de estado crítico: Evento
StateconstateChangeReason = InteractiveRejection→ notificación inmediata al equipo de plataforma. -
Capacidad pausada inesperadamente: Evento
StateconcapacityState = Suspendedfuera de ventana de mantenimiento → trigger para Power Automate que reanude la capacidad.
Limitaciones y consideraciones operativas
| Aspecto | Detalle |
|---|---|
| P SKUs con autoscale | El % de utilización no es calculable con fiabilidad porque las CUs adicionales de autoscale no se incluyen en los eventos |
| Backfill | El sistema es estrictamente real-time. No hay backfill de datos históricos al conectar un nuevo Eventstream |
| Estados iniciales | Una tabla de estados vacía equivale a NotOverloaded, no a un error de ingesta |
| Permisos | Se requiere permiso de suscripción a Fabric Events en la capacidad correspondiente |
Más información: considerations and patterns
Conclusión
Fabric Capacity Events en Real-Time Hub representa un cambio de paradigma en la observabilidad de Fabric: pasar de diagnóstico reactivo (Metrics App con horas de latencia) a detección y respuesta proactiva en tiempo real.
La combinación de eventos Summary (cada 30 segundos) con eventos State (en cada cambio) proporciona toda la señal necesaria para:
-
Detectar overages antes de que impacten en los usuarios finales.
-
Diagnosticar qué workloads están consumiendo CUs de forma inesperada.
-
Reaccionar automáticamente mediante Fabric Activator o Power Automate.
-
Analizar tendencias históricas de capacidad en Eventhouse con KQL. El único prerequisito real es empezar a recopilar datos cuanto antes: al ser un sistema estrictamente real-time, no hay manera de recuperar el histórico que no se almacenó.