Skip to main content

Watchdog de capacidade para Power BI / Microsoft Fabric — detecta consumo anômalo de CU por item e reage em degraus.

Project description

pbi-watchdog

Watchdog de capacidade para Power BI / Microsoft Fabric. Detecta itens consumindo CU muito acima do próprio padrão histórico e reage em degraus — alertar, cancelar carga em background, derrubar sessões — com travas de segurança pensadas para organizações com várias capacidades e políticas diferentes por capacidade.

Roda em qualquer lugar: notebook Fabric, Azure Function, container, GitHub Actions ou laptop. O núcleo é Python puro sobre as APIs REST; Spark e sempy são opcionais.


Em 5 minutos

pip install pbi-watchdog

pbi-watchdog init                      # gera watchdog.yaml comentado
export PBI_CLIENT_ID=...  PBI_CLIENT_SECRET=...
pbi-watchdog discover --capacities     # descobre os GUIDs das capacidades
pbi-watchdog discover --metrics        # acha o dataset do Capacity Metrics App
pbi-watchdog doctor --deep             # diz exatamente o que ainda falta
pbi-watchdog run --dry-run -v          # primeiro ciclo, sem agir

Depois agende pbi-watchdog run a cada 15 minutos.


Como funciona

A cada ciclo, por capacidade:

snapshot  →  intervalo  →  baseline  →  avaliação  →  travas  →  ação  →  auditoria
  1. Snapshot — lê do Capacity Metrics App o CU acumulado do dia por item.
  2. Intervalo — subtrai o snapshot anterior. O consumo do período é o que interessa, e é normalizado para interval_minutes: se o agendador atrasar, um intervalo de 45 min não vira um falso pico de 3x.
  3. Baseline — mediana do consumo daquele item, naquele mesmo bucket horário, nos últimos N dias, aparando o topo 10% para que um incidente passado não vire "normal".
  4. Avaliaçãoconsumo ÷ baseline cai num degrau: alert / throttle / kill.
  5. Travas — o que separa um watchdog de um gerador de incidentes (abaixo).
  6. Ação — cancela refreshes, cancela jobs Fabric, derruba sessões XMLA.
  7. Auditoria — cada decisão vira um Event, inclusive o que se decidiu não fazer e por quê.

As travas de segurança

Um detector de anomalias com poder de matar processos precisa de mais desconfiança do que um detector que só alerta. Todas são configuráveis, e nenhuma delas suprime o alerta — só limitam a ação:

Trava O que evita
min_cu_seconds Item ocioso que sai de 1 para 3 CU·s é "3x" e irrelevante
consecutive_breaches Pico instantâneo. Com 2, exige anomalia sustentada por 2 ciclos
cooldown_minutes Refresh que retenta em loop virando metralhadora de cancelamentos
max_actions_per_run Muitos itens anômalos de uma vez é sintoma sistêmico, não culpa deles — acima do orçamento, o ciclo só alerta
min_capacity_utilization_percent Matar carga numa capacidade que está a 20% de uso
protect Regulatório e executivo alertam, nunca são mortos
freeze_windows Fechamento contábil e janela de carga noturna
mode: observe Tudo acima. É o padrão, e deve continuar sendo por 2–4 semanas

Várias capacidades, políticas diferentes

defaults define a política; cada capacidade sobrescreve o que precisa. O merge é por bloco, então mexer em thresholds.alert preserva throttle e kill.

defaults:
  mode: observe
  thresholds: { alert: 1.2, throttle: 1.5, kill: 1.8 }

capacities:
  - key: F128_PROD
    id: "..."
    sku: F128
    overrides:
      guards: { consecutive_breaches: 3, max_actions_per_run: 3 }

  - key: F64_SANDBOX
    id: "..."
    sku: F64
    overrides:
      mode: enforce              # o enforcement estreia aqui
      thresholds: { alert: 1.15 }
      freeze_windows: []

Calibração

A fase de observação existe para responder a uma pergunta: com estes limiares, quantas vezes eu teria matado alguma coisa na semana passada, e o quê?

pbi-watchdog calibrate --days 14

Faz replay do histórico com a política atual e devolve quantos alertas / throttles / kills teriam ocorrido, sugestões de threshold a partir da distribuição observada, e os itens que disparariam ação repetidamente — normalmente cargas legitimamente irregulares que pertencem a protect.item_ids, não abusos.

Só depois disso troque mode para enforce, e comece pela capacidade menos crítica.


Arquitetura

src/pbi_watchdog/
  core/        baseline.py, detect.py   ← funções puras, sem I/O. É onde os testes moram
  config.py    schema pydantic          ← o contrato com o usuário
  auth/        SPN, managed identity, notebook
  sources/     metrics_app_rest | metrics_app_sempy | fake  + perfis de DAX
  storage/     sqlite | delta
  actions/     cancel_refresh, cancel_fabric_jobs, kill_xmla_sessions
  notify/      teams, slack, webhook, console
  runner.py    orquestração
  doctor.py    diagnóstico pré-voo
  calibrate.py replay do histórico
  cli.py

Cada camada é um protocolo. Trocar SQLite por outro backend é implementar 9 métodos de storage.StateStore; adicionar um canal de notificação é uma classe com um método send.

Perfis de DAX

O modelo do Capacity Metrics App muda de nome entre versões — é a causa número um de "funcionou na minha tenant e quebrou na sua". Em vez de embutir um DAX fixo, a lib declara perfis com as tabelas/colunas que cada um exige e detecta qual bate, consultando o modelo via INFO.TABLES() / INFO.COLUMNS().

pbi-watchdog inspect-model -v     # mostra o modelo e quais perfis são compatíveis

Se nenhum bater, metrics_source.dax_override aceita a sua query. Ela só precisa devolver item_id, item_name, item_kind, workspace_id, workspace_name, cu_seconds_today.


Uso como biblioteca

from pbi_watchdog import WatchdogConfig, Watchdog

config = WatchdogConfig.from_file("watchdog.yaml")
for summary in Watchdog(config, dry_run=True).run_once():
    print(summary.capacity_key, summary.anomalies, summary.actions_taken)
    for event in summary.events:
        print(event.item_name, event.tier, "→", event.effective_tier, event.suppressions)

O núcleo também é usável isolado, sem config nem storage:

from pbi_watchdog.core import baseline, detect

intervalos = baseline.derive_intervals(snapshots_atuais, snapshots_anteriores)
baselines  = baseline.compute_baselines(historico, cfg, target_bucket="h14", ...)
veredito   = detect.assess_one(intervalo, baselines["item-x"], policy, estado, now=agora)

O que você precisa provisionar

Resumo; o detalhe com passo a passo está em docs/PERMISSIONS.md, e o doctor verifica cada item.

Item Para quê Obrigatório?
Capacity Metrics App instalado fonte das métricas sim
Service principal (app registration) autenticação sim (fora do Fabric)
SPN como Viewer no workspace do Metrics App ler consumo sim
Tenant setting: Service principals can use Fabric APIs tudo sim
Tenant setting: Dataset Execute Queries REST API fonte metrics_app_rest sim
SPN em grupo de read-only admin APIs + Tenant.Read.All validar GUIDs, discover recomendado
SPN como Member/Admin dos workspaces monitorados cancelar refresh e jobs só para enforce
XMLA read-write na capacidade kill_xmla_sessions só para tier kill
Volume persistente para storage.path manter a baseline sim

Só alertar não exige permissão de escrita em lugar nenhum. Se a organização não quiser dar poder de cancelamento ao watchdog, mode: observe entrega valor sem isso.


Limitações conhecidas

  • O Capacity Metrics App tem latência de alguns minutos. A contenção nunca é instantânea — o watchdog reduz o rabo do incidente, não o previne.
  • A granularidade é o intervalo entre execuções. Um pico de 3 minutos entre dois snapshots de 15 minutos aparece diluído.
  • kill_xmla_sessions derruba usuários no meio do relatório e exige sempy/ADOMD, ou seja, só roda dentro do Fabric. Fora dele a ação falha explicitamente e o alerta continua saindo.
  • cancel_refresh só enxerga refreshes com status Unknown (o indicador de "em andamento" na API do Power BI).
  • Perder o arquivo de storage significa perder a baseline: o watchdog volta a só observar até reacumular histórico. Monte em volume persistente.
  • Rodar o watchdog na capacidade monitorada faz dele parte do consumo que ele mede. É leve, mas prefira uma capacidade diferente ou um runtime externo.

Desenvolvimento

pip install -e ".[dev]"
pytest                       # núcleo, config, CLI, doctor e end-to-end com fonte sintética
ruff check src tests

Os testes não tocam a rede: a fonte sintética e o SQLite temporário cobrem o ciclo completo, incluindo bootstrap, streak, cooldown, circuit breaker, gap do agendador e falha de ação.

Publicação

O pacote é um wheel py3-none-any padrão, sem extensão compilada.

python -m build              # gera dist/*.whl e dist/*.tar.gz
twine check dist/*

Publicar é criar uma tag — o workflow release.yml usa Trusted Publishing (OIDC), sem token guardado no repositório:

git tag v0.1.0 && git push origin v0.1.0

Antes da primeira publicação, registre o trusted publisher em https://pypi.org/manage/account/publishing/ com workflow release.yml e environment pypi.

Para validar o fluxo inteiro sem queimar a versão no PyPI (versões publicadas são imutáveis e o nome não é liberável), publique antes no TestPyPI:

twine upload --repository testpypi dist/*
pip install --index-url https://test.pypi.org/simple/ \
            --extra-index-url https://pypi.org/simple/ pbi-watchdog

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pbi_watchdog-0.1.0.tar.gz (66.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pbi_watchdog-0.1.0-py3-none-any.whl (58.5 kB view details)

Uploaded Python 3

File details

Details for the file pbi_watchdog-0.1.0.tar.gz.

File metadata

  • Download URL: pbi_watchdog-0.1.0.tar.gz
  • Upload date:
  • Size: 66.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for pbi_watchdog-0.1.0.tar.gz
Algorithm Hash digest
SHA256 453e32fb1ec7a1910368096a44d4c271fc156dc00e48004f8e457b5100c88e8e
MD5 4e4007cc0f4db093662937576427f368
BLAKE2b-256 7cd378fc4f2b61663fc5143f4707c317fd8ee36bd099dd96acc3d45284e5cbe2

See more details on using hashes here.

Provenance

The following attestation bundles were made for pbi_watchdog-0.1.0.tar.gz:

Publisher: release.yml on devrenanferrari/Watchdog-powerbi

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pbi_watchdog-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: pbi_watchdog-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 58.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for pbi_watchdog-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 e94b9540d83d1a72f0fa527bfcecb5a607c265a1784e56a48455d99b89b71a53
MD5 a88c3b5ad3278dc2bb34b6271dd1860c
BLAKE2b-256 7cd50fd25b728e721865cb29b1e3d048eba56a750d857419e97f5abc91dab14c

See more details on using hashes here.

Provenance

The following attestation bundles were made for pbi_watchdog-0.1.0-py3-none-any.whl:

Publisher: release.yml on devrenanferrari/Watchdog-powerbi

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page