first commit
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
|
||||
36
docs/regional/VALIDACAO_CORRECAO_BARGE_IN.md
Normal file
36
docs/regional/VALIDACAO_CORRECAO_BARGE_IN.md
Normal 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.
|
||||
Reference in New Issue
Block a user