Scheduler: the gone-quiet check runs two queries per account every five minutes and reloads applications it already announced #1120
Labels
No labels
accessibility
authentication
breaking change
bug
documentation
enhancement
interface
internationalisation
observability
performance
security
tier
1
tier
2
tier
3
tier/4
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
Postulo/postulo#1120
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What exists today
src/postulo/applications/quiet.py:63-116(announce_quiet_applications, called fromsend_due_reminders.py:203on every pass):owner_of(owner_id)(notifications/base.py:205-209, one query) just to read the threshold, then one query for the quiet rows (lines 82-87).quiet()goes throughwith_activity(applications/models.py:256-291), which annotates every application with a latest-event subquery, twoEXISTSsubqueries and the next-interview annotation;quiet_announced_atagainstlast_activity_at, lines 88-92) is applied in Python after the rows are loaded, so an application that went quiet weeks ago is loaded withselect_relatedof owner, profile, posting and company on every pass.So on a pass where nothing is new, the cost is 1 + 2N queries and every quiet application's row, not "about 3N"; the claimed updates happen only when something is fresh. The scout's count is corrected; the substance holds.
What would change
.filter(Q(quiet_announced_at__isnull=True) | Q(quiet_announced_at__lt=F("last_activity_at")))afterquiet()(filtering on the annotation is valid on SQLite and PostgreSQL). Rows already announced are then never loaded.User.objects.filter(is_active=True, applications_application_set__status__in=QUIET_STATUSES).select_related("profile").distinct()and pass the user tothreshold_for, dropping the per-ownerowner_ofquery. The pass is then N+1 queries and returns nothing for owners with nothing fresh.Existing tests of the notifier (
tests/for quiet announcements, including the double-scheduler claim of #221) must stay green; the claim-by-compareUPDATE(lines 99-105) is unchanged.What it saves or protects
small: about 2N+1 queries per pass (N accounts with applications), each quiet query with four correlated subqueries per application, 288 times a day, for a state that changes on the scale of days
Accessibility
none
Decisions
Found by the efficiency and reliability audit of 2026-10-30 (finding B4; index postulo/postulo#1108). Checked against
mainatdaee30b15(2026-10-30).