Skip to content

feat(agendamento): publicar o atraso do ciclo como métrica e aviso - #31

Merged
net0well merged 1 commit into
mainfrom
feature/021-metrica-de-atraso
Jul 29, 2026
Merged

net0well merged 1 commit into
mainfrom
feature/021-metrica-de-atraso

Conversation

@net0well

Copy link
Copy Markdown
Owner

Saturação do ciclo era invisível. Acima de mil empresas o excedente escorrega para o ciclo seguinte em silêncio, e quem descobria era o contador reclamando que a nota não apareceu.

A métrica é o atraso da empresa mais antiga da fila: há quanto tempo ela já deveria ter sido consultada. Escolhida por não depender de parâmetro nenhum — subir EmpresasPorCiclo zeraria uma contagem de "não enfileiradas", mesmo com o atraso continuando por falta de worker. O valor sai da primeira empresa da seleção, que já vem ordenada pela consulta mais antiga, sem custo de consulta extra.

Medidor da biblioteca padrão, não OpenTelemetry: emitir não exige dependência, só consumir exige. Instrumenta hoje e liga o coletor quando houver — e o Polly já publica no medidor dele desde a nova tentativa do object storage. Os medidores leem de campo em memória porque o valor só muda quando o ciclo roda, de trinta em trinta minutos, e consultar o banco no retorno de chamada faria uma consulta a cada raspagem.

O aviso no log dispara em quarenta e cinco minutos. Acima de um ciclo inteiro de propósito: empresa que atinge o teto de lotes volta para a fila na hora e espera até trinta minutos pelo ciclo seguinte, o que é operação normal — um e alerta que grita à toa é alerta que ninguém lê. Abaixo do prazo prometido para sobrar tempo de reagir.

O ciclo passa a enfileirar pelo IBackgroundJobClient, no lugar da API estática do Hangfire. É o que a própria biblioteca recomenda e é o que permite exercitar o ciclo sem subir o armazenamento de trabalhos — sem isso, a métrica não teria teste.

O intervalo de sondagem da fila passa a ser declarado em cinco segundos. Herdado do padrão do provedor, acrescentaria ao mesmo atraso que a
econtabil.captura.atraso_maximo (segundos)
econtabil.captura.empresas_elegiveis
econtabil.captura.empresas_enfileiradas

O atraso sai da primeira empresa da lista — a seleção já vem ordenada pela consulta mais antiga, então não custa consulta extra ao banco.

Interval fixado em 5 s, que era o item solto do relatório. Herdar o padrão do provedor acrescentaria espera ao mesmo atraso que a métrica acompanha.

Três decisões que mudei em relação ao que eu tinha te dito

O limiar não é 30 minutos, é 45. Eu errei na conta. Empresa que atinge o teto de lotes volta para a fila na hora e espera até um ciclo inteiro — 30 minutos — pelo próximo. Isso é operação normal. Um limiar de 30 dispararia sem nada estar errado, e alerta que grita à toa é alerta que ninguém lê. 45 fica acima do ruído e 15 minutos abaixo do prazo prometido. É configurável.

Troquei BackgroundJob estático por IBackgroundJobClient no ciclo de sincronização. Não era escopo, mas o job era impossível de testar sem subir o armazenamento do Hangfire — e é o que a própria biblioteca recomenda. Os outros três jobs ainda usam a API estática; fica como dívida registrada, não mexi neles.

A verificação em produção não aconteceu ainda. As três empresas estão agendadas para 03:07 e 03:30 UTC, e agora são 02:48 — nenhuma elegível, que é o estado saudável. O ciclo roda a cada 30 minutos, então o log aparece na virada. Os quatro testes cobrem os caminhos, inclusive lendo a métrica por um teste que só chamasse RegistrarCiclo provariaque o campo foi escrito, não que a métrica sai.

E uma coisa que a conta do SLA revelou

SemNovidade = 1h: empresa sem novidade só volta a ser consultada uma hora depois. Se uma nota chega logo após a checagem, ela espera até uma hora inteira só para ser detectada — antes de qualquer fila, worker ou processamento. O orçamento de 1 hora já está estourado por política, não por gargalo.

A métrica que acabei de entregar mede o atraso da fila, que é a parte que EmpresasPorCiclo e Workers resolvem. Ela não vai acusar esse outro atraso, porque ele não é saturação — é a frequência configurada funcionando como projetada.

Para prometer 1 hora com folga, IntervaloSemNovidade teria que cair para 20 ou 30 minutos. O custo disso é direto: dobra ou triplica as consultas por CNPJ, e a cota da SEFAZ é por CNPJ somando todos os sistemas. É exatamente o botão que causou os bloqueios 656 que investigamos.

Essa é uma decisão de negócio, não técnica — quanto risco de bloqueio vale um prazo menor. Não mexi em nada.

feat(agendamento): publicar o atraso do ciclo como métrica e aviso

Saturação do ciclo era invisível. Acima de mil empara o ciclo seguinte em silêncio, e quem descobria era o contador reclamando que a nota não apareceu.

A métrica é o atraso da empresa mais antiga da fila: há quanto tempo ela já deveria ter sido consultada. Escolhida por não depender de parâmetro nenhum — subir EmpresasPorCiclo zeraria uma contagem de "não enfileiradas", mesmo com o atraso continuando por falta de worker. O valor sai da primeira empresa da seleção, que já vem ordenada pela consulta mais antiga, sem custo de consulta extra.

Medidor da biblioteca padrão, não OpenTelemetry: emitir não exige dependência, só consumir exige. Instrumenta hoje e liga o coletor quando hno medidor dele desde a nova tentativa do object storage. Os medidores leem de campo em memória porque o valor só muda quando o ciclo roda, de trinta em trinta minutos, e consultar o banco no retorno de chamada faria uma consulta a cada rasp

O aviso no log dispara em quarenta e cinco minutos. Acima de um ciclo inteiro de propósito: empresa que atinge o teto de lotes volta para a fila na hora e espera até trinta minutos pelo ciclo seguinte, o que é operação normal — um limiar menor gritaria à toa, e alerta que grita à toa é alerta que ninguém lê. Abaixo do prazo prometido para sobrar tempo de reagir.

O ciclo passa a enfileirar pelo IBackgroundJobClient, no lugar da API estática do Hangfire. É o que a própria biblioteca recomenda e é o que permite exercitar o ciclo sem subir o armazenamento de trabalhos — sem isso, a métrica
O ciclo passa a enfileirar pelo IBackgroundJobCli do Hangfire. É o que a própria biblioteca recomenda e é o que permite exercitar o ciclo sem subir o armazenamento de trabalhos — sem isso, a métrica não teria teste.

O intervalo de sondagem da fila passa a ser declado do padrão do provedor, acrescentaria ao mesmo atraso que a métrica acompanha.

Saturação do ciclo era invisível. Acima de mil empresas o excedente escorrega para o ciclo
seguinte em silêncio, e quem descobria era o contador reclamando que a nota não apareceu.

A métrica é o atraso da empresa mais antiga da fila: há quanto tempo ela já deveria ter sido
consultada. Escolhida por não depender de parâmetro nenhum — subir EmpresasPorCiclo zeraria
uma contagem de "não enfileiradas", mesmo com o atraso continuando por falta de worker. O
valor sai da primeira empresa da seleção, que já vem ordenada pela consulta mais antiga, sem
custo de consulta extra.

Medidor da biblioteca padrão, não OpenTelemetry: emitir não exige dependência, só consumir
exige. Instrumenta hoje e liga o coletor quando houver — e o Polly já publica no medidor
dele desde a nova tentativa do object storage. Os medidores leem de campo em memória porque
o valor só muda quando o ciclo roda, de trinta em trinta minutos, e consultar o banco no
retorno de chamada faria uma consulta a cada raspagem.

O aviso no log dispara em quarenta e cinco minutos. Acima de um ciclo inteiro de propósito:
empresa que atinge o teto de lotes volta para a fila na hora e espera até trinta minutos
pelo ciclo seguinte, o que é operação normal — um e alerta que
grita à toa é alerta que ninguém lê. Abaixo do prazo prometido para sobrar tempo de reagir.

O ciclo passa a enfileirar pelo IBackgroundJobClient, no lugar da API estática do Hangfire.
É o que a própria biblioteca recomenda e é o que permite exercitar o ciclo sem subir o
armazenamento de trabalhos — sem isso, a métrica não teria teste.

O intervalo de sondagem da fila passa a ser declarado em cinco segundos. Herdado do padrão
do provedor, acrescentaria ao mesmo atraso que a
econtabil.captura.atraso_maximo         (segundos)
econtabil.captura.empresas_elegiveis
econtabil.captura.empresas_enfileiradas

O atraso sai da primeira empresa da lista — a seleção já vem ordenada pela consulta mais antiga, então não custa consulta extra ao banco.

Interval fixado em 5 s, que era o item solto do relatório. Herdar o padrão do provedor acrescentaria espera ao mesmo atraso que a métrica acompanha.

Três decisões que mudei em relação ao que eu tinha te dito

O limiar não é 30 minutos, é 45. Eu errei na conta. Empresa que atinge o teto de lotes volta para a fila na hora e espera até um ciclo inteiro — 30 minutos — pelo próximo. Isso é operação normal. Um limiar de 30 dispararia sem nada estar errado, e alerta que grita à toa é alerta que ninguém lê. 45 fica acima do ruído e 15 minutos abaixo do prazo prometido. É configurável.

Troquei BackgroundJob estático por IBackgroundJobClient no ciclo de sincronização. Não era escopo, mas o job era impossível de testar sem subir o armazenamento do Hangfire — e é o que a própria biblioteca recomenda. Os outros três jobs ainda usam a API estática; fica como dívida registrada, não mexi neles.

A verificação em produção não aconteceu ainda. As três empresas estão agendadas para 03:07 e 03:30 UTC, e agora são 02:48 — nenhuma elegível, que é o estado saudável. O ciclo roda a cada 30 minutos, então o log aparece na virada. Os quatro testes
cobrem os caminhos, inclusive lendo a métrica por um teste que só chamasse RegistrarCiclo provariaque o campo foi escrito, não que a métrica sai.

E uma coisa que a conta do SLA revelou

SemNovidade = 1h: empresa sem novidade só volta a ser consultada uma hora depois. Se uma nota chega logo após a checagem, ela espera até uma hora inteira só para ser detectada — antes de qualquer fila, worker ou processamento. O orçamento de 1 hora já está estourado por política, não por gargalo.

A métrica que acabei de entregar mede o atraso da fila, que é a parte que EmpresasPorCiclo e Workers resolvem. Ela não vai acusar esse outro atraso, porque ele não é saturação — é a frequência configurada funcionando como projetada.

Para prometer 1 hora com folga, IntervaloSemNovidade teria que cair para 20 ou 30 minutos. O custo disso é direto: dobra ou triplica as consultas por CNPJ, e a cota da SEFAZ é por CNPJ somando todos os sistemas. É exatamente o botão que causou os bloqueios 656 que investigamos.

Essa é uma decisão de negócio, não técnica — quanto risco de bloqueio vale um prazo menor. Não mexi em nada.

feat(agendamento): publicar o atraso do ciclo como métrica e aviso

Saturação do ciclo era invisível. Acima de mil empara o ciclo
seguinte em silêncio, e quem descobria era o contador reclamando que a nota não apareceu.

A métrica é o atraso da empresa mais antiga da fila: há quanto tempo ela já deveria ter sido
consultada. Escolhida por não depender de parâmetro nenhum — subir EmpresasPorCiclo zeraria
uma contagem de "não enfileiradas", mesmo com o atraso continuando por falta de worker. O
valor sai da primeira empresa da seleção, que já vem ordenada pela consulta mais antiga, sem
custo de consulta extra.

Medidor da biblioteca padrão, não OpenTelemetry: emitir não exige dependência, só consumir
exige. Instrumenta hoje e liga o coletor quando hno medidor
dele desde a nova tentativa do object storage. Os medidores leem de campo em memória porque
o valor só muda quando o ciclo roda, de trinta em trinta minutos, e consultar o banco no
retorno de chamada faria uma consulta a cada rasp

O aviso no log dispara em quarenta e cinco minutos. Acima de um ciclo inteiro de propósito:
empresa que atinge o teto de lotes volta para a fila na hora e espera até trinta minutos
pelo ciclo seguinte, o que é operação normal — um limiar menor gritaria à toa, e alerta que
grita à toa é alerta que ninguém lê. Abaixo do prazo prometido para sobrar tempo de reagir.

O ciclo passa a enfileirar pelo IBackgroundJobClient, no lugar da API estática do Hangfire.
É o que a própria biblioteca recomenda e é o que permite exercitar o ciclo sem subir o
armazenamento de trabalhos — sem isso, a métrica
O ciclo passa a enfileirar pelo IBackgroundJobCli do Hangfire.
É o que a própria biblioteca recomenda e é o que permite exercitar o ciclo sem subir o
armazenamento de trabalhos — sem isso, a métrica não teria teste.

O intervalo de sondagem da fila passa a ser declado do padrão
do provedor, acrescentaria ao mesmo atraso que a métrica acompanha.
@net0well
net0well merged commit 6d75788 into main Jul 29, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant