惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Microsoft Azure Blog
Microsoft Azure Blog
WordPress大学
WordPress大学
小众软件
小众软件
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
V
V2EX
Hugging Face - Blog
Hugging Face - Blog
美团技术团队
博客园 - 三生石上(FineUI控件)
Last Week in AI
Last Week in AI
酷 壳 – CoolShell
酷 壳 – CoolShell
博客园 - Franky
Microsoft Security Blog
Microsoft Security Blog
Y
Y Combinator Blog
A
About on SuperTechFans
The GitHub Blog
The GitHub Blog
U
Unit 42
H
Hackread – Cybersecurity News, Data Breaches, AI and More
云风的 BLOG
云风的 BLOG
IT之家
IT之家
MyScale Blog
MyScale Blog
V
Visual Studio Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
I
InfoQ
博客园 - 司徒正美

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant
O bug de 16 minutos: quando 'dado faltando' é uma corrida...
William Scussel · 2026-06-25 · via DEV Community
Cover image for O bug de 16 minutos: quando 'dado faltando' é uma corrida contra o relógio

William Scussel

"Seu sistema está perdendo dados"

Um cliente abriu o chamado, convicto. O relatório de retorno bancário enviado por e-mail toda manhã tinha 423 linhas. O mesmo relatório, gerado sob demanda no portal, tinha 1.351.

928 linhas, sumidas. É o tipo de número que faz você presumir o pior.

No fim, nada foi perdido. O bug tinha 16 minutos de largura.

Passo 1: comparar antes de debugar

Nada de código ainda. Primeiro dei um diff nos dois arquivos.

  • Mesmo dia.
  • Mesmo banco.
  • Mesmo filtro de status.
  • Toda linha do arquivo do e-mail estava contida no arquivo do portal.

Ou seja, o dado não estava errado. Estava ausente. Problema diferente.

Passo 2: matar hipóteses com prova, não com opinião

Três causas plausíveis, cada uma derrubada em produção com queries read-only:

"Está dividido entre bancos / anexos."
Não. Todas as 1.351 linhas pertenciam ao mesmo código de banco.

"O dedup contra o dia anterior é agressivo demais."
O relatório subtrai faturas já vistas no dia anterior:

$diff = array_diff(
    array_column($hoje, 'invoice'),
    array_column($ontem, 'invoice')
);

Repliquei contra os dados de produção. Removeu zero linhas. Não era o culpado.

"Os dois relatórios filtram colunas de data diferentes."
Não. Os dois filtravam a mesma coluna transaction_created_at, para a mesma data.

Passo 3: a mesma query, rodada agora, retorna tudo

Foi aqui que a ficha caiu. Com os filtros exatos que o job do e-mail usa:

SELECT COUNT(DISTINCT invoice)
FROM   bank_returns
WHERE  DATE(occurrence_date) = '2026-06-23'
  AND  bank_code = 33
  AND  credit_date IS NOT NULL;   -- "somente pagos"
-- → 1351

O e-mail tinha enviado 423. O banco de dados agora guarda 1.351. Com filtros idênticos. Nada na query mudou. Algo no tempo mudou.

Passo 4: seguir os timestamps

07:15:45  job do relatório roda, monta e envia o e-mail
07:31:02  sistema importa o arquivo de retorno do banco (~12.700 lançamentos do dia)

O relatório roda às 07:15. O arquivo com a maior parte das baixas confirmadas do dia chega às 07:31. O e-mail é gerado 16 minutos antes de o dado existir no banco.

Separe as faturas por esse corte e o gap bate exato:

-- importadas até 07:15  → o que o e-mail viu   → 423
-- importadas após 07:15 → "faltando"           → 928
-- total                                        → 1351

O portal "viu mais" por um motivo chato: foi consultado às 08:23, depois da importação.

O bug de verdade

Não é lógica. É acoplamento temporal entre uma tarefa agendada e a chegada de um dado externo. O relatório assume que os pagamentos de ontem já estão totalmente carregados às 07:15. O banco discorda.

Correções, da mais barata para a melhor:

  • Rodar o relatório depois da importação matinal.
  • Melhor: disparar o relatório ao fim da importação, em vez de um horário fixo.
  • Defensivo: o relatório validar que a importação esperada rodou antes de reportar.

A lição

"Menos linhas" quase nunca é "perdemos dados". Geralmente é "olhei no momento errado".

Antes de anexar um debugger, faça duas perguntas:

  1. Quando esse dado nasce?
  2. Quando eu o leio?

A maioria dos bugs de "dado faltando" morre aí mesmo.