Skip to content

feat(lint): flag loops that open a savepoint per iteration inside a transaction - #131032

Draft
ldelvoye wants to merge 2 commits into
masterfrom
ldelvoye/feat/savepoint-loop-lint
Draft

ldelvoye wants to merge 2 commits into
masterfrom
ldelvoye/feat/savepoint-loop-lint

Conversation

@ldelvoye

Copy link
Copy Markdown
Member

resolves INFRENG-846

Adds flake8 rule S034: it flags a loop that runs inside a transaction and opens a savepoint on every iteration (a nested atomic block, or get_or_create / update_or_create and their async versions). Once one transaction holds more than 64 savepoints that wrote something, Postgres overflows its subtransaction cache and every query on that database slows down while the transaction stays open.

What it catches: the transaction and the loop in the same function, the savepoint opened directly in the loop body. That includes @transaction.atomic functions, outbox_context(transaction.atomic(...)) blocks, and comprehensions.

What it does not catch, on purpose, to stay a cheap per-file check: a transaction opened by a caller, a savepoint opened by a function the loop calls (including a model's own save()), and anything decided at run time. It also cannot tell a loop over a short fixed list from one over customer data, so short fixed loops need a # noqa: S034 with a reason. Sizes and leaked transactions are left to production monitoring and to the task connection cleanup in #130665.

The 11 existing loops in src/sentry are pinned in a shrink-only S034_allowlist, like S030. getsentry loads this plugin, so getsentry/getsentry#23210 exempts its three hits and has to merge first.

…ransaction

S034 catches the single-function shape: a loop inside an atomic block
whose body opens a nested atomic block or calls get_or_create or
update_or_create. Past 64 such savepoints in one transaction Postgres
overflows its subtransaction cache and slows every query. Existing
loops are pinned in a shrink-only allowlist.
Class bodies run where they are defined, so they keep the enclosing
transaction; async queryset methods open savepoints too.
@linear-code

linear-code Bot commented Nov 13, 2026

Copy link
Copy Markdown

INFRENG-846

@github-actions github-actions Bot added the Scope: Backend Automatically applied to PRs that change backend components label Nov 13, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Scope: Backend Automatically applied to PRs that change backend components

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant