Files
SGF/docs/MODULE_ASSOCIATION_CONCURRENCY_REVIEW.md
T
2026-11-02 20:29:34 +02:00

71 lines
9.1 KiB
Markdown

# Fila de associações — leituras concorrentes e confirmação
Continuação de 02/11/2026: a [consolidação de carga e libertação dos bloqueios](MODULE_ASSOCIATION_LOAD_CONSOLIDATION.md) identifica a espera no `FOR UPDATE` da empresa e verifica quatro resultados após commit/rollback, sem duplicação. As 440 leituras deste relatório foram preservadas e não repetidas. A limitação de não observar o resultado após libertação, nesta prova original, é agora coberta pela prova separada; a capacidade de implantação continua pendente.
02/11/2026. Continuação da [projecção de referências](MODULE_ASSOCIATION_PROJECTION_DELIVERY.md), **sem alterar o código funcional** já medido. Avaliação nova de concorrência sintética, sem repetir as suites válidas anteriores. A revisão visual e a capacidade de implantação continuam separadas.
## Âmbito e preparação
PHP 8.4.27; base **sgf_tempo_test**, role **sgf_test_runner**, cluster **sgf_modular_regression_2576427d1939**, porta **55439**. Foram preparados 3 000 registos por área, 25 pares de rascunhos com 100 linhas/serviços distintos por rascunho e descrições de 1 000 bytes por linha. A página de 25 rascunhos referencia 2 500 serviços. Existe ruído de outro tenant e unidade não seleccionada, como nas fixtures anteriores.
São **quatro identidades sintéticas novas**, com consulta administrativa explicitamente configurada apenas no novo âmbito QA. Uma identidade dispõe também de `clients.edit` nesse âmbito para a confirmação sintética desfeita. Não se modificaram contas/direitos da instalação SGF, de 8039 ou de outros âmbitos anteriores.
Para processos independentes verem as mesmas linhas, **a nova fixture foi gravada exclusivamente na base de regressão e ficou retida**, com manifesto privado fora da raiz web/repositório. Não se declara rollback desta preparação. Não se apagou ou reinicializou a base. O manifesto identifica o âmbito para diagnóstico; não contém palavras-passe. Entradas privadas dos trabalhadores contêm contexto/tokens de prova e não integram os artefactos públicos.
Foram usados 1/2/4 processos PHP independentes, cada um com identidade e sessão distintas, aquecimento e barreira de arranque. Há três ondas por cenário e cinco pedidos sequenciais por processo. Os leitores executam em **transacção PostgreSQL READ ONLY**, com timeout SQL de 3 s; o coordenador impõe prazos de arranque/conclusão e termina apenas os seus próprios processos em falha.
O pedido percorre o kernel HTTP, middleware, autorização e SQL reais, com autenticação previamente preparada. Não usa servidor HTTP externo, login/MFA, TLS, proxy, navegador ou sessões reais de cliente. O tempo de arranque dos processos foi registado separadamente e excluído da janela principal de leitura.
## Resultados das leituras
Página de 25 registos. P50/P95 são percentis **descritivos da amostra**, pelo método nearest rank; não são garantias de cauda ou SLA. A taxa é a observada neste circuito fechado, incluindo validação entre pedidos, não capacidade máxima sustentada.
| Índice na prova | Área | Processos | Pedidos | P50 ms | P95 da amostra ms | Pedidos/s observados |
| --- | --- | ---: | ---: | ---: | ---: | ---: |
| Sem índice experimental | Clientes | 1 | 15 | 35,86 | 51,07 | 24,61 |
| Sem índice experimental | Clientes | 2 | 30 | 35,73 | 39,46 | 50,32 |
| Sem índice experimental | Clientes | 4 | 60 | 37,99 | 60,81 | 80,58 |
| Sem índice experimental | Facturação, 100 linhas | 1 | 15 | 298,01 | 476,93 | 3,11 |
| Sem índice experimental | Facturação, 100 linhas | 2 | 30 | 264,37 | 358,30 | 6,92 |
| Sem índice experimental | Facturação, 100 linhas | 4 | 60 | 429,46 | 495,43 | 9,57 |
| Revisão experimental | Clientes | 1 | 15 | 11,54 | 13,48 | 65,64 |
| Revisão experimental | Clientes | 2 | 30 | 11,08 | 12,16 | 132,32 |
| Revisão experimental | Clientes | 4 | 60 | 14,79 | 21,40 | 207,56 |
| Revisão experimental | Facturação, 100 linhas | 1 | 15 | 99,51 | 157,65 | 8,47 |
| Revisão experimental | Facturação, 100 linhas | 2 | 30 | 102,92 | 188,29 | 14,36 |
| Revisão experimental | Facturação, 100 linhas | 4 | 60 | 102,86 | 121,34 | 33,81 |
As **420 leituras da matriz** concluíram, sem limites SQL atingidos. Os intervalos medidos confirmaram sobreposição efectiva de 1/2/4 pedidos em todas as ondas correspondentes, não apenas processos configurados. Cada resposta foi validada contra o hash esperado da fixture; identidades diferentes receberam a mesma resposta autorizada.
Mantiveram-se 11 consultas por pedido de clientes e 31 por pedido de facturação. A memória incremental máxima por processo/pedido ficou perto de **0,09 MiB** e **4,85 MiB**, respectivamente. Não se deve multiplicar esses valores para inferir o consumo total do servidor: faltam kernel/processos, PostgreSQL, sessões e demais serviços.
O índice experimental de revisão tinha nome único por execução. Foi **gravado na base sintética para ficar visível aos outros processos e removido explicitamente no final**. Não se declara rollback dessa criação entre processos. A ausência do índice foi verificada; o catálogo anterior ficou igual. Nenhum índice foi criado/removido no destino ou na demonstração persistente.
## Leituras durante uma confirmação e espera de outro decisor
Numa transacção exterior, a API confirmou uma associação **apenas para um cliente novo da fixture** e manteve os bloqueios de empresa/registo. Enquanto a decisão permanecia sem commit, quatro leitores fizeram mais **20 pedidos**, todos com a resposta anterior esperada e sobreposição efectiva de quatro. A leitura MVCC não expôs a decisão não gravada.
Uma segunda conferência do mesmo cliente chamou o serviço de confirmação noutro processo. Foi observada espera real em `pg_stat_activity`, seguida de **SQLSTATE 55P03** ao atingir o `lock_timeout=1000ms` configurado exclusivamente nesse processo: cerca de **1 044 ms**. O chamador directo registou o erro de base de dados; este cenário não mede a apresentação HTTP desse timeout ao utilizador.
A primeira transacção foi **desfeita**. A contagem de eventos de associação do novo âmbito permaneceu igual à anterior à prova; a segunda chamada não gravou decisão. Não se decidiu nenhuma das seis associações protegidas. As provas anteriores de confirmações concorrentes com commit normal continuam válidas e não foram repetidas nesta passagem.
## Evidência e preservação
O coordenador passou **1 ensaio / 346 asserções**. Recolheu ainda a conclusão dos 89 subprocessos de teste: 88 leitores (84 da matriz + quatro da prova mista) e um concorrente de confirmação. Total: **440 leituras medidas completas**, mais o aquecimento; sem falhas nos leitores. Não se somam aqui as asserções internas dos trabalhadores às do coordenador.
[Medições por onda/pedido](proofs/module-association-concurrency-20261102.json) · [resumo, percentis e hashes](proofs/module-association-concurrency-summary-20261102.json).
Foram comparados os IDs e hashes das linhas **que já existiam antes** nas oito tabelas de registos/identidade, bem como o catálogo de índices, depois da prova. Permaneceram iguais. As novas linhas QA e quatro contas sintéticas são adicionais e retidas apenas nessa base; não são confundidas com preservação de contagem global ou com implantação de perfis. As sequências não foram repostas.
Os seis registos protegidos, a cache bloqueada, o código funcional e o trabalho alheio permaneceram intactos. Não houve ligação ao SGF local/8039, concessão real, publicação, activação de Compras ou novo checkpoint. Tokens, credenciais e manifestos privados não foram copiados para o relatório.
## Limites e repetição
A carga é curta, em uma empresa/unidade, com quatro identidades e um único login PostgreSQL de QA; não valida multi-tenant concorrente, grande número de sessões, saturação, arranque frio, dimensionamento de pool, custo de escrita prolongada ou implantação/recuperação de índices. O cluster é partilhado com outra base sintética. Os valores descritivos das amostras de 15/30/60 pedidos não validam percentis de produção ou capacidade de implantação.
O ensaio **não altera a política de timeout da aplicação**. A espera controlada foi exercitada directamente no serviço; tratamento HTTP, retries operacionais e comunicação visual de um timeout continuam a precisar de avaliação própria. A revisão visual permanece pendente, sem nova tentativa pela via bloqueada.
O launcher fixado aceita `scripts/module-association-compare.mjs concurrency`, após `sync` da cópia de regressão existente. Uma nova execução cria outro âmbito sintético e um manifesto privado, pelo que deve ser deliberada; não repete por rotina testes válidos, não reseta a base e não remove as fixtures anteriores. Os trabalhadores só aceitam entradas privadas sob o directório da execução e conferem a identidade física da base. `scripts/summarize-association-concurrency.mjs <relatorio-privado.json>` gera o resumo sem executar testes ou consultar bases.
Esta prova amplia a evidência sintética de concorrência. **Revisão visual, aceitação deste incremento e validação da capacidade de implantação continuam separadas.**