Calendar entries from a plugin: add_reminder rewrites an unchanged entry on every sync, so the dashboard's figures are worked out again each hour #1164

Closed
opened 2026-10-31 03:04:27 +00:00 by tiagoagueda · 1 comment
Owner

What exists today

tiagoagueda/postulo-francetravail on the forge's main (033cd90), src/postulo_francetravail/account.py:270-311 _calendar: on every run, for each of the coming MONTHS_AHEAD = 3 months (line 57), it calls api.add_reminder for every wanted entry (the declaration, its reminder, the payment: up to three a month) and counts each one in report.pushed, whether or not anything changed.

Core, src/postulo/applications/services.py:1073-1140 add_reminder: when the uid already exists it assigns summary, note, due date, retired_at = None and actor, and calls save(update_fields=[…, "updated_at"]) unconditionally (lines 1122-1139). So every run moves updated_at on 6 to 9 reminders that did not change.

src/postulo/applications/analytics.py:339-420 fingerprint includes Max("updated_at") of the person's reminders (lines 374-376, 399-401) in the insights cache key, and insights_for (lines 422-441) rebuilds the figures on a miss (build, from line 444, loads every application with its posting, company and industries). So each France Travail run invalidates the dashboard's figures, and the next view of the dashboard (core/widgets.py:375) pays the full build. The same holds for any other plugin or calendar import that calls add_reminder again with the same values.

The connection's report also says "N pushed" on every run although nothing was pushed.

What would change

Core: in add_reminder, compare the incoming values with the stored ones (summary cut to 250, note, due_at, retired_at is None, actor cut to its field) and return without saving when they are equal. To let a caller report honestly, also say whether anything was written, either as a second return value under a new name or as an attribute on the returned reminder (for example reminder.changed), keeping the current return type for existing callers. A test asserts that a second identical call leaves updated_at and the insights fingerprint unchanged.

tiagoagueda/postulo-francetravail, once it pins that core: count report.pushed only for entries that were created or changed.

What it saves or protects

small: 6 to 9 needless UPDATEs per France Travail run stop, and with them the insights cache miss they cause: the next dashboard view after every run (hourly by default) no longer rebuilds the figures from every application, event and listing

Accessibility

none

Decisions

  • Split into: a core issue (add_reminder skips an unchanged entry and says whether it wrote) and a small postulo-francetravail issue (count only what changed), the second after the first.

Found by the efficiency and reliability audit of 2026-10-30 (finding PR13; index postulo/postulo#1108). Checked against main at daee30b15 (2026-10-30).

## What exists today tiagoagueda/postulo-francetravail on the forge's `main` (`033cd90`), `src/postulo_francetravail/account.py:270-311` `_calendar`: on every run, for each of the coming `MONTHS_AHEAD = 3` months (line 57), it calls `api.add_reminder` for every wanted entry (the declaration, its reminder, the payment: up to three a month) and counts each one in `report.pushed`, whether or not anything changed. Core, `src/postulo/applications/services.py:1073-1140` `add_reminder`: when the uid already exists it assigns summary, note, due date, `retired_at = None` and actor, and calls `save(update_fields=[…, "updated_at"])` unconditionally (lines 1122-1139). So every run moves `updated_at` on 6 to 9 reminders that did not change. `src/postulo/applications/analytics.py:339-420` `fingerprint` includes `Max("updated_at")` of the person's reminders (lines 374-376, 399-401) in the insights cache key, and `insights_for` (lines 422-441) rebuilds the figures on a miss (`build`, from line 444, loads every application with its posting, company and industries). So each France Travail run invalidates the dashboard's figures, and the next view of the dashboard (`core/widgets.py:375`) pays the full build. The same holds for any other plugin or calendar import that calls `add_reminder` again with the same values. The connection's report also says "N pushed" on every run although nothing was pushed. ## What would change Core: in `add_reminder`, compare the incoming values with the stored ones (summary cut to 250, note, `due_at`, `retired_at is None`, actor cut to its field) and return without saving when they are equal. To let a caller report honestly, also say whether anything was written, either as a second return value under a new name or as an attribute on the returned reminder (for example `reminder.changed`), keeping the current return type for existing callers. A test asserts that a second identical call leaves `updated_at` and the insights fingerprint unchanged. tiagoagueda/postulo-francetravail, once it pins that core: count `report.pushed` only for entries that were created or changed. ## What it saves or protects small: 6 to 9 needless `UPDATE`s per France Travail run stop, and with them the insights cache miss they cause: the next dashboard view after every run (hourly by default) no longer rebuilds the figures from every application, event and listing ## Accessibility none ## Decisions - **Split into:** a core issue (`add_reminder` skips an unchanged entry and says whether it wrote) and a small postulo-francetravail issue (count only what changed), the second after the first. --- Found by the efficiency and reliability audit of 2026-10-30 (finding PR13; index postulo/postulo#1108). Checked against `main` at `daee30b15` (2026-10-30).
tiagoagueda added this to the 0.6.0 milestone 2026-10-31 03:04:27 +00:00
Author
Owner

The other half of this finding is tiagoagueda/postulo-francetravail#21.

The other half of this finding is tiagoagueda/postulo-francetravail#21.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Postulo/postulo#1164
No description provided.