## TL;DR

Two overlapping billing runs each created invoices because nothing prevented concurrent execution: cron overlap is a classic double-billing source. Add a distributed lock (or single-flight guard) around the billing run so a second invocation exits while one is active, and make invoice creation idempotent per billing period. Then void or credit the duplicates and reconcile.

```text
agent's scheduled billing run executed twice: cron overlap created double invoices
```

## Use this when

- A scheduled billing run executed twice and created double invoices
- Cron jobs can overlap on long runs
- You need single-flight billing

## Not for this skill when

- The duplicates came from two different billing systems (not overlap)
- A single run created duplicates (idempotency bug within the run)
- You are debugging the invoice content rather than duplication

## Steps

1. Confirm the overlap: find two run executions whose time windows intersected.
   Expected: The cause is proven.
2. Identify the duplicate invoices per customer and billing period.
   Expected: The damage is scoped.
3. Void or credit the duplicates and notify affected customers.
   Expected: The books and the customers are made whole.
4. Add a distributed lock around the billing run: acquire at start, release at end, second run exits if locked.
   Expected: Overlaps are structurally impossible.
5. Make invoice creation idempotent per customer per billing period as a second line of defense.
   Expected: Even a lock failure cannot double-bill.
6. Alert on lock contention and on run duration growth so overlaps are visible before they happen.
   Expected: The operations picture is complete.

## Tool compatibility

Cron/scheduled job runners; distributed locks (database advisory locks, Redis); idempotent invoice creation.

## Variant phrasings

### cron overlap double invoices billing

The mechanism phrased directly.

### billing run executed twice duplicate

The symptom phrasing.

### distributed lock scheduled billing run

The fix as a phrase.

## Why it happens

Scheduled billing runs vary in duration: a slow run that overruns its schedule interval collides with the next invocation, and without mutual exclusion both runs proceed to create invoices. Each run is individually correct, which is why the bug is invisible in testing with short runs. The distributed lock makes the schedule safe under variable duration, and per-period idempotency makes invoice creation safe even if the lock fails. Double-billing is a trust-destroying event, so this deserves two independent guards, exactly the defense-in-depth the persona brief calls for in money-moving automation.

## Edge cases / pitfalls

- Locks need expiry: a crashed run must not hold the lock forever.
- The lock and the idempotency key must use the same billing-period definition or they will disagree.
- Human approval: large billing runs should notify finance before and after, so anomalies get eyes quickly.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_fQsg5X328KSluFEFqBwhIw
