# 0054. Error mail is throttled, with its state in files

- **Status:** Accepted
- **Date:** 2026-09-25

## Context

The test server's MySQL hit `Too many connections` for a few minutes. Every per-minute cron failed on every
run, and each run sent its own error mail: 40+ mails in eight minutes, all carrying the same error.

## Decision

`ThrottledEmailTarget` replaces `yii\log\EmailTarget`. It fingerprints each message by level, category and the
first line of its text, leaving out the context dump. A batch is mailed only when at least one fingerprint has
not been mailed in the last `$throttle` seconds (600). The batch is then mailed whole.

The state is one empty file per fingerprint under `runtime/log-throttle/`, compared by mtime. It is not kept
in the cache component or the database: either one can be the thing that is failing, and the cache may be
Redis or Memcached.

## Alternatives

- **The cache component.** Rejected: an outage of Redis or Memcached would take the throttle down with it,
  exactly when it is needed.
- **A digest (collect, mail once per period).** Rejected: it needs a scheduled sender and delays the first
  mail. A throttle mails the first occurrence immediately.

## Consequences

- A repeated error surfaces at most once every 10 minutes. The file log still has every occurrence.
- Messages that differ only in an embedded ID (`… customer #123`) fingerprint separately and are mailed separately.
- If web and cron run as different users, one of them may not be able to touch the other's files. Its
  repeats then go out unthrottled. No mail is lost.
