first commit

This commit is contained in:
2026-08-21 09:44:08 -03:00
parent 881a99b0a8
commit c0a657b7f7
14 changed files with 910 additions and 83 deletions

View File

@@ -231,7 +231,7 @@ As conexões WebSocket já estabelecidas não são redirecionadas e continuam no
## 9. Renovação escalonada das conexões
Manter 50 sockets abertos indefinidamente sem renovação é arriscado porque serviços upstream normalmente aplicam TTL e renovação de autorização.
Manter um pool grande de sockets aberto indefinidamente sem renovação é arriscado porque serviços upstream normalmente aplicam TTL e renovação de autorização.
A configuração padrão usa:
@@ -249,9 +249,55 @@ WS03 -> ~509s
...
```
Somente conexões livres são renovadas. Isso evita um evento no qual 50 conexões expiram e fazem handshake simultaneamente.
Somente conexões livres são renovadas. Isso evita que todo o pool expire e faça handshake simultaneamente.
## 10. Alta disponibilidade regional
## 10. Barge-in e reutilização segura do pool
Barge-in ocorre quando o usuário interrompe a fala do TTS antes de `audio.done`. A versão corrigida não descarta automaticamente um WebSocket saudável nem permite que áudio residual contamine a próxima síntese.
Fluxo:
```text
usuário interrompe
|
v
TIA cancela a utterance e envia text.clear
|
v
sidecar cancela imediatamente o relay de audio.delta
|
v
envia text.clear ao xAI
|
v
drena e DESCARTA audio.delta/audio.done residuais
|
v
recebe audio.clear
|
+--> confirmado: devolve audio.clear ao TIA e libera o WS saudável ao pool
|
`--> timeout/erro: fecha o WS; maintenance cria substituto pré-aquecido
```
Enquanto aguarda `audio.clear`, nenhum frame residual é encaminhado ao LiveKit. Isso cria um boundary limpo entre a utterance cancelada e a próxima.
Configuração:
```text
XAI_POOL_BARGE_IN_CLEAR_TIMEOUT_S=1.0
```
Métricas específicas:
```text
tia_xai_pool_barge_ins_total
tia_xai_pool_barge_in_reuses_total
tia_xai_pool_barge_in_resets_total
tia_xai_pool_barge_in_discarded_messages_total
```
## 11. Alta disponibilidade regional
Operação normal:
@@ -267,7 +313,7 @@ Se ORD perder saúde/capacidade xAI, os slots começam a falhar e a quantidade d
Não há necessidade de alterar o cliente ou o LiveKit para escolher a região.
## 11. Escala horizontal
## 12. Escala horizontal
A capacidade teórica de pool é:
@@ -291,19 +337,19 @@ IAD: 2 pods x 50 = 100
TOTAL = 200
```
### Restrição crítica
### Capacidade efetivamente provisionada
`replicas * XAI_POOL_SIZE` **não pode ultrapassar o limite real concedido pela OCI para o endpoint/tenancy/região**.
`XAI_POOL_SIZE` é **somente o tamanho configurado do pool por réplica TIA**; não representa um limite público do OCI/xAI. Neste ambiente, a capacidade foi negociada diretamente com xAI/OCI e pode ser muito superior aos exemplos de 50 conexões usados neste documento.
Se a OCI disser que o limite 50 é global por endpoint, então duas réplicas de 50 no mesmo endpoint seriam incorretas. Nesse caso use, por exemplo:
O dimensionamento correto é:
```text
2 replicas x 25 = 50 total
conexões pré-aquecidas da região = réplicas_region * XAI_POOL_SIZE
```
ou obtenha endpoints/capacidades independentes.
e deve ser comparado com a **capacidade efetivamente negociada/provisionada** para aquela região/endpoint. Exemplos com 25/50 existem apenas para facilitar a leitura da arquitetura.
## 12. Escala visual
## 13. Escala visual
```text
Carga baixa

View File

@@ -30,3 +30,13 @@ O modo anterior permanece disponível. O deployment regional é opcional e não
- parsing YAML dos manifests renderizados: PASS.
Não foi executado teste real contra OCI xAI, pois depende das credenciais/endpoints do ambiente TIM/OCI. O manual descreve smoke, saturação, failover e stress test a executar em FQA.
## Correção — barge-in e capacidade negociada
- relay upstream passou a ser assíncrono para que `text.clear` seja processado imediatamente durante `audio.delta`;
- barge-in cancela o relay, envia `text.clear` ao xAI e drena mensagens residuais até `audio.clear`;
- socket volta ao pool somente após boundary confirmado; timeout/erro força reset e reposição do slot;
- adicionadas métricas de barge-in/reuso/reset/descarte;
- `XAI_POOL_SIZE` documentado como tamanho configurável por réplica, sem assumir limite público de 50 conexões;
- capacidade total passa a ser dimensionada conforme acordo/provisionamento real xAI/OCI.

View File

@@ -70,7 +70,7 @@ IAD_XAI_SECRET_NAME=xai-iad-credentials
## 5. Definir tamanho do pool
Para um Pod com 50 sockets:
`XAI_POOL_SIZE` é o número de conexões xAI pré-aquecidas mantidas por réplica TIA; **não é um limite do serviço OCI/xAI**. Ajuste-o conforme a capacidade negociada/provisionada. Exemplo com 50 sockets:
```bash
XAI_POOL_SIZE=50
@@ -90,6 +90,15 @@ XAI_POOL_UNAVAILABLE_FREE=0
XAI_POOL_RECOVER_FREE=5
```
Para barge-in, configure também:
```bash
XAI_POOL_BARGE_IN_CLEAR_TIMEOUT_S=1.0
```
Esse timeout limita quanto tempo o sidecar espera pelo `audio.clear` que confirma que o WebSocket está limpo após uma interrupção. Se não houver confirmação, o socket é descartado e substituído.
### Importante
Se houver `N` réplicas apontando para o mesmo endpoint:
@@ -98,7 +107,7 @@ Se houver `N` réplicas apontando para o mesmo endpoint:
sockets máximos = N * XAI_POOL_SIZE
```
Nunca configure isso acima da quota xAI real.
Dimensione esse total de acordo com a capacidade efetivamente negociada/provisionada para a região/endpoint.
## 6. Criar Secrets regionais

View File

@@ -14,7 +14,7 @@ Validar separadamente capacidade do pool, comportamento do Kubernetes, failover
## Camada 2 — Prewarm
Subir com `XAI_POOL_SIZE=50` e medir:
Subir com um `XAI_POOL_SIZE` representativo da configuração alvo (50 abaixo é apenas exemplo) e medir:
- tempo total até Ready;
- taxa de sucesso de handshake;
@@ -64,11 +64,32 @@ Observe por 5 minutos.
Esperado:
- sockets são renovados individualmente;
- não existe burst de 50 reconnects;
- não existe burst de reconnects equivalente ao tamanho total do pool;
- slots ocupados não são renovados no meio da síntese;
- pool retorna ao tamanho configurado.
## Camada 6 — Falha upstream
## Camada 6 — Barge-in / clean boundary
Com uma síntese longa em andamento:
1. aguardar pelo menos um `audio.delta`;
2. simular interrupção do usuário;
3. confirmar envio de `text.clear` ao sidecar;
4. fazer o fake/provider enviar 1 ou mais `audio.delta` residuais antes de `audio.clear`;
5. confirmar que os frames residuais **não** chegam ao LiveKit;
6. confirmar `audio.clear` entregue ao TIA;
7. confirmar `leased` retorna ao valor anterior sem fechar o socket;
8. iniciar nova utterance e validar ausência de áudio da utterance cancelada.
Critérios:
- `tia_xai_pool_barge_ins_total` incrementa;
- `tia_xai_pool_barge_in_reuses_total` incrementa quando `audio.clear` é confirmado;
- `tia_xai_pool_barge_in_discarded_messages_total` contabiliza frames residuais;
- se `audio.clear` não chegar dentro de `XAI_POOL_BARGE_IN_CLEAR_TIMEOUT_S`, `tia_xai_pool_barge_in_resets_total` incrementa e o slot é recriado.
## Camada 7 — Falha upstream
Bloqueie ORD ou aponte temporariamente para endpoint inválido.
@@ -80,7 +101,7 @@ Esperado:
- Service deixa de enviar novas chamadas a ORD;
- IAD continua Ready.
## Camada 7 — Latência
## Camada 8 — Latência
Compare três cenários:
@@ -101,7 +122,7 @@ Meça:
Hipótese: o hop localhost adiciona latência desprezível frente ao TTFB do provider, enquanto remove handshake xAI do caminho crítico na situação normal.
## Camada 8 — Carga semelhante a produção
## Camada 9 — Carga semelhante a produção
Evite somente burst C=200. Use sockets persistentes e concorrência de síntese representativa da operação real, seguindo a metodologia que produziu resultados reprodutíveis nos testes anteriores.
@@ -115,7 +136,7 @@ Rodar pelo menos:
120% por janela curta
```
## Camada 9 — Rollout
## Camada 10 — Rollout
Com chamadas ativas:

View File

@@ -0,0 +1,36 @@
# Validação da Correção — Barge-in e Pool xAI
## Escopo
A correção torna o relay upstream cancelável durante uma síntese e preserva o WebSocket somente após confirmação explícita de boundary limpo (`audio.clear`).
## Comportamento validado
Sequência simulada após barge-in:
```text
TIA -> text.clear
xAI -> audio.delta (residual; descartado)
xAI -> audio.done (residual; descartado)
xAI -> audio.clear (boundary confirmado)
```
Resultado esperado e observado no teste focado:
- `text.clear` é enviado ao upstream;
- mensagens residuais são drenadas localmente;
- frames residuais não são encaminhados ao LiveKit;
- `audio.clear` confirma que o socket pode ser reutilizado;
- se não houver `audio.clear` no timeout, o slot é marcado unhealthy, fechado e posteriormente recriado pelo maintenance loop.
## Validações executadas neste ambiente
- `python -m compileall -q src`: PASS;
- parse YAML dos 6 manifests regionais renderizados: PASS;
- teste focado `_clear_slot_and_wait` com 2 mensagens residuais antes de `audio.clear`: PASS;
- suíte existente `tests/adapters/test_xai_tts.py`: não executada por falta do pacote `oci` no runtime de validação;
- `kubectl --dry-run`: não executado porque `kubectl` não está instalado no runtime; os manifests foram validados por parser YAML.
## Capacidade
`XAI_POOL_SIZE` representa apenas o tamanho do pool por réplica TIA. A capacidade total deve seguir o provisionamento/acordo real do ambiente xAI/OCI, sem assumir o limite público de 50 conexões.