> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lerian.studio/llms.txt
> Use this file to discover all available pages before exploring further.

# Como o Streaming Hub funciona

> O caminho que um evento percorre pelo Streaming Hub: ingestão e classificação, deduplicação consume-once, match de assinaturas, despacho, retentativas, dead-lettering e desativação automática.

Um evento se move pelo Streaming Hub em três estágios: o hub **ingere** o evento a partir do stream interno, faz o **match** dele contra as suas assinaturas e o **despacha** para cada destino que deu match. Esta página percorre cada estágio e as garantias de entrega que decorrem dele.

## Ingerindo eventos do stream

***

O Streaming Hub consome o stream da plataforma como mensagens **CloudEvents 1.0** em **modo de conteúdo binário**: os atributos de contexto do CloudEvents trafegam nos cabeçalhos do registro Kafka (cada um com o prefixo `ce-`) e o corpo do evento é o valor do registro. O hub lê o roteamento e a identidade a partir dos cabeçalhos sem desserializar o payload.

Todo registro que o hub aceita precisa carregar este conjunto de contexto:

| Cabeçalho          | Requisito                                                                                                            |
| ------------------ | -------------------------------------------------------------------------------------------------------------------- |
| `ce-specversion`   | A versão da especificação CloudEvents.                                                                               |
| `ce-id`            | Um id de evento único. **Deve ser um UUIDv7** — é a chave de deduplicação e correlação.                              |
| `ce-source`        | O serviço produtor.                                                                                                  |
| `ce-type`          | O tipo de evento, exatamente `studio.lerian.<resource>.<event>`.                                                     |
| `ce-time`          | O timestamp de emissão.                                                                                              |
| `ce-schemaversion` | A versão do esquema do payload.                                                                                      |
| `ce-resourcetype`  | O segmento de recurso (por exemplo, `account`).                                                                      |
| `ce-eventtype`     | O segmento de evento (por exemplo, `created`).                                                                       |
| `ce-tenantid`      | O tenant proprietário, e a única fonte de identidade de tenant na ingestão. Um registro sem ele vai para quarentena. |

Para cada registro, o hub retorna um de três **veredictos**:

| Veredicto      | Quando                                                                     | Resultado                                                                                                                        |
| -------------- | -------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| **Aceitar**    | Um evento bem formado para um tenant conhecido e ativo.                    | Persistido no inbox de eventos e submetido ao match contra as assinaturas.                                                       |
| **Descartar**  | Um evento de sistema, ou um evento para um tenant desconhecido ou inativo. | Contabilizado e ignorado; a posição no stream ainda avança. Nenhum evento é armazenado.                                          |
| **Quarentena** | Um evento malformado, ou um evento sem seu tenant.                         | Registrado como um evento poison para análise forense. Não é retentado — um registro malformado nunca se torna válido no replay. |

O tenant admitido na ingestão vem apenas do atributo `ce-tenantid` validado que o parser extraiu. Um tenant desconhecido ou inativo é descartado no gate do roster — o único ponto em que o isolamento por tenant é imposto no caminho de ingestão.

<Note>
  Três strings relacionadas se parecem, mas são distintas — nunca as confunda:

  * **`ce-type`** — o tipo CloudEvents: `studio.lerian.<resource>.<event>` (por exemplo, `studio.lerian.transaction.posted`).
  * **Tópico Kafka** — onde o evento trafega no barramento interno. Não há um prefixo único válido para toda a plataforma: cada produtor tem seu próprio namespace de tópico. O Midaz roteia para tópicos explícitos com um segmento de serviço fixo — os eventos do ledger trafegam em `lerian.streaming.ledger_<resource>.<event>`, com o serviço incorporado ao primeiro segmento (assim `transaction.posted` trafega em `lerian.streaming.ledger_transaction.posted`) e qualquer hífen no recurso ou no evento convertido em um sublinhado no tópico (`balance.config-changed` trafega em `lerian.streaming.ledger_balance.config_changed`). Outros produtores — o Consignado e os comandos entre produtos — derivam seu namespace de seu `ce-source`.
  * **`X-Lerian-Event-Type`** — o tipo estampado em um webhook entregue: apenas o final `<resource>.<event>` do `ce-type` (`transaction.posted`). Espelha a identidade do `ce-type`, não o tópico Kafka — não carrega nenhum segmento de serviço do produtor (sem a incorporação `ledger_`).

  Veja a [visão geral de event streaming](/pt/reference/events/overview) para o contrato completo do wire.
</Note>

## Deduplicação consume-once

***

O stream interno é at-least-once, então o mesmo registro pode chegar mais de uma vez. No caminho de entrada para o inbox de eventos, o hub deduplica por `ce-id`: um id duplicado não grava nada e é contabilizado como um descarte por dedup. Os registros são persistidos por partição Kafka em uma única transação, e a posição no stream para uma partição é confirmada apenas depois que a gravação daquela partição é confirmada — de modo que uma falha em uma partição nunca perde nem confirma em duplicidade eventos em outra.

## Match de assinaturas

***

Uma vez que um evento é armazenado, o hub resolve quais das suas assinaturas devem recebê-lo. O match de assinaturas é interno e **catalog-free**: ele avalia cada evento contra as suas assinaturas por `(tenant, tipo de evento, schema major)` diretamente, sem consultar o catálogo de eventos. Um tipo de evento que nenhuma assinatura deseja produz zero entregas — um resultado correto, não um erro.

Uma assinatura é admitida no match somente quando está **`enabled`** e em **`verification_state = active`**. Essas são duas condições independentes — veja [o modelo de assinatura](/pt/streaming-hub/managing-subscriptions) — e o match exige ambas.

## Despachando para os seus destinos

***

Para cada match, o hub cria um job de entrega e o entrega a um pool de workers (oito workers por padrão). Os workers reivindicam jobs vencidos de forma atômica com um lease curto e se intercalam entre tenants, de modo que o backlog de nenhum tenant faz os outros passarem fome. Cada worker carrega o payload armazenado, decripta em memória o segredo de assinatura ou a credencial do destino, e faz exatamente uma tentativa de entrega ao sink.

A entrega é **at-least-once**: o hub pode entregar o mesmo evento mais de uma vez (através de retentativas ou de re-entregas após o reinício de um worker). Toda entrega carrega um `X-Lerian-Event-Id` estável (o `ce-id`) para você deduplicar, e um `X-Lerian-Delivery-Id` por tentativa que muda a cada retentativa. Trate um `X-Lerian-Event-Id` repetido como uma duplicata e confirme-o sem reprocessar. Veja [Consumindo eventos](/pt/streaming-hub/consuming-events) para o lado do consumidor desse contrato.

## Retentativas e back-off

***

Quando uma tentativa falha, o hub agenda a próxima em uma curva de back-off fixa com full jitter:

```
0 · 5s · 5m · 30m · 2h · 5h · 10h · 10h
```

A curva abrange cerca de 28 horas ao longo dos seus oito passos. Cada assinatura pode sobrescrevê-la com o seu próprio cronograma (até 12 passos, cada um limitado a 10 horas); uma sobrescrita malformada recai na curva padrão em vez de falhar a entrega.

## Dead-lettering

***

Um evento cujas retentativas se esgotaram é enviado para **dead-letter** — o hub para de tentá-lo e registra o resultado terminal. Um job que, em vez disso, fica derrubando um worker no meio da tentativa — nunca registrando um resultado — é recuperado um número limitado de vezes (cinco por padrão) e então enviado para dead-letter como poison, de modo que um único job tóxico jamais ocupe um worker para sempre.

## Circuit breaker

***

Cada par `(tenant, destino)` tem um circuit breaker. Quando um destino falha repetidamente, seu breaker abre e os jobs seguintes para aquele destino são **descartados** — reagendados sem uma tentativa — para que um único endpoint quebrado não queime a capacidade dos workers nem martele um alvo em dificuldades. O breaker se recupera sozinho assim que o destino volta a ter sucesso.

## Desativando automaticamente um destino quebrado

***

Um destino que permanece quebrado por muito tempo é desativado automaticamente. A desativação automática só dispara quando o span de falha aberto é **ao mesmo tempo**:

* **sustentado** — vem falhando por pelo menos a janela de falha (120 horas por padrão); e
* **espalhado** — pelo menos 12 horas separam a primeira e a última falha do span.

Ambos os gates precisam valer, e uma **única entrega bem-sucedida limpa o span**, de modo que uma pane breve nunca se acumula em direção ao veredicto. Quando a desativação automática dispara, ela vira a flag `enabled` da assinatura para `false` — nunca toca em `verification_state`. A entrega para (o match exige `enabled`), e o hub registra o motivo.

Você recupera uma assinatura desativada automaticamente com `POST /v1/subscriptions/:id/verify`, que re-sonda o destino e, em caso de sucesso, o reabilita no lugar. A desativação automática é governada por um kill switch (`STREAMING_HUB_AUTODISABLE_ENABLED`), então um operador pode entregá-la desligada. Veja [recuperando uma assinatura desativada automaticamente](/pt/streaming-hub/managing-subscriptions).

## Garantias de ordenação

***

O stream interno é particionado por tenant, então os eventos de um tenant normalmente trafegam por uma única partição e o hub preserva a ordem **first-in, first-out** deles de ponta a ponta. O hub atribui e deduplica pelos cabeçalhos CloudEvents, não pela chave do registro Kafka, então um produtor que distribui (aplica salt) um tenant quente entre várias partições muda apenas o posicionamento físico — o hub ainda atribui e deduplica corretamente.

O único trade-off é a ordenação: os eventos de um tenant com salt abrangem múltiplas partições sem garantia de ordem entre partições, então esse tenant abre mão do FIFO estrito. A sequência de chegada que o hub atribui reflete a ordem em que os eventos *chegaram* ao hub, não a ordem em que foram *produzidos*. Um tenant sem salt mantém o FIFO de partição única por toda a extensão.

## Próximos passos

***

<CardGroup cols={2}>
  <Card title="Gerenciando assinaturas" icon="gear" href="/pt/streaming-hub/managing-subscriptions">
    O modelo de assinatura, os fluxos de onboarding e a rotação de segredos.
  </Card>

  <Card title="Consumindo eventos" icon="inbox" href="/pt/streaming-hub/consuming-events">
    Verifique assinaturas, deduplique e consuma eventos por pull.
  </Card>
</CardGroup>
