GEMINI LABJP
API — Gemini 3.5 Flash is generally available and now powers gemini-flash-latest for sustained agentic and coding performanceAGENT — Managed Agents enter public preview, running stateful autonomous agents in Google-hosted isolated Linux sandboxesSEARCH — File Search adds multimodal search, embedding and searching images natively with gemini-embedding-2RESEARCH — A new Deep Research agent adds collaborative planning, visualization, MCP server integration, and File SearchSHEETS — Gemini in Sheets analyzes surrounding data to diagnose and fix formula errors in one clickROADMAP — Gemini 3.5 Pro slips to July for refinement; the Flash line leads for nowAPI — Gemini 3.5 Flash is generally available and now powers gemini-flash-latest for sustained agentic and coding performanceAGENT — Managed Agents enter public preview, running stateful autonomous agents in Google-hosted isolated Linux sandboxesSEARCH — File Search adds multimodal search, embedding and searching images natively with gemini-embedding-2RESEARCH — A new Deep Research agent adds collaborative planning, visualization, MCP server integration, and File SearchSHEETS — Gemini in Sheets analyzes surrounding data to diagnose and fix formula errors in one clickROADMAP — Gemini 3.5 Pro slips to July for refinement; the Flash line leads for now
Articles/Advanced
Advanced/2026-06-27Advanced

Your Gemini Completion Event Will Arrive Twice — An Idempotent Sink That Makes Webhook + Reconciliation Effectively Once-Only

Once you receive Gemini long-running operations over a Webhook and back it up with a reconciliation poller, the same completion arrives twice and publishing or billing runs twice. Build an idempotent sink with a normalized key and a claim-run-commit pattern that keeps side effects effectively once-only.

gemini90webhook2idempotency2batch-api2production122

Premium Article

Right after you move long-running operations from polling to a Webhook and then add a reconciliation poller as a safety net, a different bug surfaces: the same batch completion gets processed twice. A generated article gets published twice, or two completion notifications go out.

This is not a side effect of adding reconciliation. The moment you have two delivery paths, duplicates are structurally unavoidable. If the reconciliation story — events still drop the instant you deploy is about recovering missed terminal events, this article is about the other half: what to do when recovery means you now grab the same completion twice. The fix is to make the sink idempotent, so that no matter how many times an event arrives, the side effect runs exactly once.

Why double-processing happens — the dual path is the premise, not the accident

Gemini's webhook delivery is at-least-once. If the connection drops before your receiver returns 2xx, Google can't confirm success and re-delivers the same event. Even if you processed it successfully but only the 2xx response failed, the redelivery still happens. So even a webhook on its own must be built assuming a completion can arrive twice.

Add a reconciliation poller and the duplicate paths multiply.

Where duplicates come fromWhat's happening
Webhook redeliveryDisconnect before 2xx → Google re-delivers the same event
Webhook racing the pollerThe low-frequency poller independently detects the same completion while the webhook is mid-handler
Double receipt during deployOld instance starts processing → can't respond during cutover → redelivered to the new instance
Manual retryAn operator re-runs the poller by hand and re-submits a completion that isn't committed yet

The key is to stop trying to plug these individually as exceptional cases. You can't seal every path. Instead, make the sink so that calling it any number of times produces the same result, and the number of paths stops mattering. Idempotency isn't an effort to reduce the number of entrances — it's a design that funnels everything into a single exit.

The shape — split the sink into "decision" and "side effect"

The trick to preventing double-processing is to put one gate between receiving the completion event and triggering the side effect (publish, bill, notify). The gate's job is to decide, atomically, whether anyone has already triggered the side effect for this completion.

Split it into three phases.

  1. Normalize — extract a stable idempotency key from the incoming event
  2. Claim — assert "I will process this completion" first, and reject contenders
  3. Commit — run the side effect to completion, then record it as done

Both the webhook receiver and the reconciliation poller just call this same sink at the end. There can be many entrances, but only one function triggers the side effect.

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
If your webhook-plus-reconciliation dual path keeps running completion handlers twice and duplicating publishes or notifications, you'll get a design that collapses them to effectively once
You'll be able to normalize an idempotency key from the operation name and enforce a claim-run-commit cycle backed by a SQLite UNIQUE constraint, with runnable code
Including how to retry a side effect that fails midway and how to size the claim TTL, so you can run unattended pipelines without fear of double-processing
Secure payment via Stripe · Cancel anytime

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Gemini Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

Related Articles

Advanced2026-06-14
Trusting Gemini Structured Output in Production — Schema Design, Double Validation, and Bounded Retries
Gemini's structured output guarantees parseable JSON, not correct values. Notes on schema design with @google/genai, why propertyOrdering matters, a Zod double-validation layer, handling MAX_TOKENS truncation, and a bounded-retry extraction pipeline.
Advanced2026-06-13
Gemini's GA Image Models Won't Output Exact Device Resolutions — A Wallpaper Pipeline That Fixes Aspect Ratio and Safe Areas
After switching to the GA image models, your wallpapers no longer fit the screen. Here's how to crop one master image into every device resolution and cut your generation count to a fraction, with full Pillow code.
Advanced2026-04-27
Self-Healing Architecture for Gemini Computer Use — Production Patterns That Keep Browser Automation Alive Beyond Day Three
Gemini Computer Use looks magical in demos but breaks daily in production: vanishing elements, surprise modals, network jitter, off-by-four-pixel clicks. This guide builds a five-layer self-healing architecture in Python that classifies failures and recovers them automatically, with working code you can drop into your agent loop today.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →