Skip to content

Refactor reminders for draft challenge requests#4729

Open
chrisvanrun wants to merge 5 commits into
mainfrom
4721-draft-request-reminders-not-send-often-enough
Open

Refactor reminders for draft challenge requests#4729
chrisvanrun wants to merge 5 commits into
mainfrom
4721-draft-request-reminders-not-send-often-enough

Conversation

@chrisvanrun
Copy link
Copy Markdown
Member

Closes #4721

Unlike the follow-up date, the draft ChallengeRequest reminders is operating on a time window which doesn't quite work.

Thanks to Miriam for spotting this:

If the request was made on 21-4 then there is a check on 1-5 (too young: 10 days), on 14-5 (23 days: reminder), and then on 1-6 (40 days: too old).

Instead of breaking my head over a window date range that might work, I simplified things with a straight forward counter.

Frequency of them being sent is the frequency of the task, unchanged and is every 1st and 14th of the month.

It also reduces the age at which reminders starting to get sent to a minimum of 7 days.

Any current requests still in draft will receive a few extra reminders for the next few weeks. Which IMHO is fine. I intentionally did not add a migration step to counter that.

@chrisvanrun chrisvanrun requested a review from jmsmkn as a code owner May 22, 2026 09:47
@chrisvanrun chrisvanrun linked an issue May 22, 2026 that may be closed by this pull request
@chrisvanrun chrisvanrun changed the title 4721 draft request reminders not send often enough Refactor reminders for draft challenge requests May 22, 2026
@chrisvanrun chrisvanrun requested a review from amickan May 22, 2026 09:47
Comment thread app/grandchallenge/challenges/tasks.py
),
)
draft_reminder_count = models.PositiveSmallIntegerField(
default=0,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This field should not be editable.

):
send_challenge_requests_draft_reminder(challenge_request=c)
c.draft_reminder_count += 1
c.save(update_fields=["draft_reminder_count"])
Copy link
Copy Markdown
Member

@jmsmkn jmsmkn May 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The task is not a singleton so it would be more robust to do this with a single update:

requests = ChallengeRequest.objects.filter(
        status=ChallengeRequest.ChallengeRequestStatusChoices.DRAFT,
        created__lte=now()
        - settings.CHALLENGE_REQUEST_AGE_START_DRAFT_REMINDER_CUTOFF,
        draft_reminder_count__lt=settings.CHALLENGE_REQUEST_MAX_DRAFT_REMINDERS,Expand commentComment on line R248Resolved
    )

for request in requests:
    send_challenge_requests_draft_reminder(challenge_request=request)

requests.update(draft_reminder_count=F("draft_reminder_count") + 1)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is superior in that it would prevent an additional DB query per reminder! I am not sure why you would say it is more robust? Any failure would be caught by the transaction wrapper, and doing the update in a single call wouldn't catch other spawned (same) tasks to also send the email afaik.

Copy link
Copy Markdown
Member

@jmsmkn jmsmkn May 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The task is not a singleton, so n-tasks can run at the same time. Updating the value in python takes the read value and increments it. If n tasks run at the same time, they read draft_reminder_count as 0, and then all set it to 1. But n emails have been sent. Using F(...) does the update in the database, so the counter gets updated correctly. See https://docs.djangoproject.com/en/6.0/ref/models/expressions/#f-expressions

Copy link
Copy Markdown
Member Author

@chrisvanrun chrisvanrun May 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aaaaah! The increment is applied at the commit of a transaction if using an F() construct, and a pure increment in that it's not calculating the new value during the transaction but only at the time of commit in the DB. Yep, way robuster!

Today I learned something new! Thank you!

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Draft request reminders not send often enough.

3 participants