fix(lark): durable DB dedup for due-date reminder (stop repeat DMs)#3
Merged
Merged
Conversation
lark_due_reminder_task deduped only via a 25h Redis key. When the deployment cache is unavailable / non-shared / evicting the key is lost and the hourly beat re-DMs the same assignee for the same issue every hour (observed: dozens of repeats). The original "missing mark" diagnosis was wrong -- a mark existed but was not durable. Replace the Redis dedup with a durable LarkDueReminderLog row claimed atomically via get_or_create on a unique (issue, receiver, stage, reminder_date) constraint -- idempotent across the hourly cadence and across concurrent beat workers, surviving cache loss/restart by construction. Mirrors EmailNotificationLog + WorkspaceMember's soft-delete-aware unique idiom. A claim is released via hard delete on any failure so a later run still retries (slot consumed only on a confirmed send -- same intent as before, now durable). - model LarkDueReminderLog + migration 0124 - task: Redis cache dedup -> get_or_create claim; docstring updated - 3 pytest cases (dedup across runs, retry-on-failure, disabled), verified locally 3/3 (repo CI runs no python suite) Pre-existing automation RenameIndex migration drift (would be 0125) is deliberately NOT included -- unrelated, belongs to the automation-merge owner.
Owner
Author
|
Admin-merging: CI fully green (this PR touches no JS/TS, so the pre-existing frontend Reviewer caveat carried from the description: the repo CI runs no Python suite, so the dedup logic was verified locally — pytest 3/3 (dedup-across-runs, retry-on-failure, disabled-noop), not by CI. The spam only actually stops once this is deployed and migration |
JOBYINC
pushed a commit
that referenced
this pull request
May 17, 2026
Re-based onto the lark-stable line (this branch builds the production ghcr.io/jobyinc/plane-*:lark-stable images). Same fix as preview PR #3 (commit 1cb3908): replace the non-durable 25h Redis dedup in lark_due_reminder_task with a durable LarkDueReminderLog row claimed atomically via get_or_create on a unique (issue,receiver,stage,reminder_date) constraint; claim released via hard delete on failure so retry still works. Mirrors EmailNotificationLog + WorkspaceMember soft-delete-unique idiom. Migration = 0123_larkduereminderlog depending on 0122_automationrule_automationrulerun (this branch's actual head; it has no 0123_workitemfield — that is custom-fields/preview only). Verified locally pytest 3/3 on the source branch. Repo CI runs no python test suite. Effect requires this image rebuilt + droplet pull + the 0123 migration applied.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
lark_due_reminder_task(hourly Celery beat) was DM'ing the sameassignee about the same issue dozens of times. The reported cause —
"missing 已提醒 mark" — is wrong: a mark existed, but it was a 25h
Redis key (
cache.get/set). When the deployment's cache isunavailable / non-shared across workers / evicting, the key never
sticks, so every hourly run re-detects the issue and re-sends.
Fix
Replace the cache-only dedup with a durable
LarkDueReminderLogrow, claimed atomically via
get_or_createon a unique(issue, receiver, stage, reminder_date)constraint:workers, regardless of cache health — fixed by construction, no DO
access needed.
EmailNotificationLogsibling +WorkspaceMember's soft-delete-aware unique idiom(
unique_togetherincl.deleted_at+ partialUniqueConstraint(condition=deleted_at__isnull=True)).run still retries — the once/stage/day slot is consumed only on a
confirmed send (same intent as the old Redis check, now durable).
Hard delete (not soft) because a failed claim has no audit value and
soft-delete would leave a ghost row + queue a pointless cascade task
per failure.
Changes
LarkDueReminderLogmodel + migration0124lark_due_reminder_task: Redis dedup →get_or_createclaim; docstring updatedTest plan
pytest plane/tests/unit/bg_tasks/test_lark_due_reminder_task.py→ 3/3 pass locally:LARK_NOTIFICATIONS_ENABLEDunset ✅manage.py check— 0 issues;makemigrations --check— model fully captured by01240124applied on the environment running the beat.Reviewer notes
RenameIndexmigration drift (would be0125) is deliberately excluded — unrelated to this fix, predates it, belongs to the automation-merge owner (same pre-existing-debt family as the documentedcheck:types/check:formatitems onpreview).