Skip to content

Conversation

@RainzDev
Copy link
Contributor

@RainzDev RainzDev commented Jun 22, 2025

Description

The remindme command used tasks.loop to check for reminders, which wasn't ideal. Instead, this PR changes how the remindme works and should be able to send reminders right on time.

Guidelines

  • My code follows the style guidelines of this project (formatted with Ruff)

  • I have performed a self-review of my own code

  • I have commented my code, particularly in hard-to-understand areas

  • I have made corresponding changes to the documentation if needed

  • My changes generate no new warnings

  • I have tested this change

  • Any dependent changes have been merged and published in downstream modules

  • I have added all appropriate labels to this PR

  • I have followed all of these guidelines.

How Has This Been Tested? (if applicable)

Ran the remindme command within tux dev bot.

Screenshots (if applicable)

Please add screenshots to help explain your changes.

Additional Information

Please add any other information that is important to this PR.

Summary by Sourcery

Replace periodic polling of reminders with precise scheduling via asyncio.call_later to send reminders on time.

New Features:

  • Schedule existing reminders on bot startup using call_later instead of polling.
  • Schedule new reminders immediately after creation using call_later.

Bug Fixes:

  • Eliminate up-to-120-second delay by removing tasks.loop for polling and using direct scheduling.

Enhancements:

  • Remove the get_unsent_reminders method and periodic check_reminders loop.
  • Automatically delete reminder entries from the database after sending.

@sourcery-ai
Copy link
Contributor

sourcery-ai bot commented Jun 22, 2025

Reviewer's Guide

This PR replaces the polling-based reminder loop with precise scheduling via bot.loop.call_later, ensuring reminders fire on time, cleans up sent reminders, and streamlines initialization and UI messages.

Sequence diagram for scheduling and sending reminders with call_later

sequenceDiagram
    participant User as actor User
    participant Bot as Bot
    participant DB as DatabaseController

    User->>Bot: /remindme command
    Bot->>DB: insert_reminder(...)
    DB-->>Bot: reminder_obj
    Bot->>Bot: bot.loop.call_later(seconds, send_reminder(reminder_obj))
    Note over Bot: After 'seconds' delay
    Bot->>DB: delete_reminder_by_id(reminder_obj.reminder_id)
    Bot->>User: Send reminder message
Loading

Class diagram for updated RemindMe cog and reminder scheduling

classDiagram
    class RemindMe {
        - bot: Tux
        - db: DatabaseController
        - _initialized: bool
        + send_reminder(reminder: Reminder)
        + on_ready()
        + remindme(ctx, seconds, reminder)
    }
    class DatabaseController {
        + get_all_reminders()
        + insert_reminder(...)
        + delete_reminder_by_id(reminder_id)
    }
    class Reminder {
        + reminder_id: int
        + reminder_user_id: int
        + reminder_content: str
        + reminder_expires_at: datetime
    }
    RemindMe --> DatabaseController
    RemindMe --> Reminder
Loading

File-Level Changes

Change Details Files
Replace polling loop with call_later scheduling
  • Remove tasks.loop check_reminders, before_loop hook, and loop.start call
  • Remove get_unsent_reminders method from the DB controller
  • Introduce _initialized flag and on_ready listener to schedule pending reminders
  • Schedule each new reminder immediately using bot.loop.call_later
tux/cogs/utility/remindme.py
tux/database/controllers/reminder.py
Clean up sent reminders
  • Add deletion of reminder by ID in send_reminder
  • Add error handling for deletion failures
tux/cogs/utility/remindme.py
Update reminder command UI
  • Remove outdated note about potential 120-second delivery delay
tux/cogs/utility/remindme.py

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@github-actions
Copy link
Contributor

github-actions bot commented Jun 22, 2025

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

@cloudflare-workers-and-pages
Copy link

cloudflare-workers-and-pages bot commented Jun 22, 2025

Deploying tux with  Cloudflare Pages  Cloudflare Pages

Latest commit: e063768
Status: ✅  Deploy successful!
Preview URL: https://0eb966da.tux-afh.pages.dev
Branch Preview URL: https://remindme-revamp.tux-afh.pages.dev

View logs

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey @RainzDev - I've reviewed your changes and found some issues that need to be addressed.

Blocking issues:

  • Potential issue with passing coroutine to asyncio.create_task in call_later. (link)
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments

### Comment 1
<location> `tux/cogs/utility/remindme.py:144` </location>
<code_context>

             logger.error(f"Error creating reminder: {e}")

+        self.bot.loop.call_later(seconds, asyncio.create_task, self.send_reminder(ctx.author, reminder_obj))
+
         await ctx.reply(embed=embed, ephemeral=True)
</code_context>

<issue_to_address>
Potential issue with passing coroutine to asyncio.create_task in call_later.

create_task requires a coroutine object, not a function and arguments. Use a lambda to wrap the call: self.bot.loop.call_later(seconds, lambda: asyncio.create_task(self.send_reminder(ctx.author, reminder_obj))).
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.


logger.error(f"Error creating reminder: {e}")

self.bot.loop.call_later(seconds, asyncio.create_task, self.send_reminder(ctx.author, reminder_obj))
Copy link
Contributor

Choose a reason for hiding this comment

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

issue (bug_risk): Potential issue with passing coroutine to asyncio.create_task in call_later.

create_task requires a coroutine object, not a function and arguments. Use a lambda to wrap the call: self.bot.loop.call_later(seconds, lambda: asyncio.create_task(self.send_reminder(ctx.author, reminder_obj))).

@codecov
Copy link

codecov bot commented Jun 22, 2025

Codecov Report

Attention: Patch coverage is 0% with 23 lines in your changes missing coverage. Please review.

Project coverage is 8.92%. Comparing base (1afca03) to head (e063768).
Report is 28 commits behind head on main.

✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
tux/cogs/utility/remindme.py 0.00% 22 Missing ⚠️
tux/database/controllers/reminder.py 0.00% 1 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff            @@
##            main    #920      +/-   ##
========================================
- Coverage   8.92%   8.92%   -0.01%     
========================================
  Files        121     121              
  Lines      10269   10328      +59     
  Branches    1255    1322      +67     
========================================
+ Hits         917     922       +5     
- Misses      9278    9327      +49     
- Partials      74      79       +5     
Flag Coverage Δ *Carryforward flag
database 0.30% <ø> (+<0.01%) ⬆️ Carriedforward from 2c7af6a
integration 5.92% <0.00%> (-0.01%) ⬇️
unit 6.38% <0.00%> (-0.01%) ⬇️

*This pull request uses carry forward flags. Click here to find out more.

Components Coverage Δ
Core Bot Infrastructure 16.45% <ø> (ø)
Database Layer 0.00% <0.00%> (ø)
Bot Commands & Features 0.00% <0.00%> (ø)
Event & Error Handling ∅ <ø> (∅)
Utilities & Helpers ∅ <ø> (∅)
User Interface Components 0.00% <ø> (ø)
CLI Interface ∅ <ø> (∅)
External Service Wrappers ∅ <ø> (∅)

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@RainzDev
Copy link
Contributor Author

Not done yet tho, obviously, since on_ready needs and will be included for persistent reminding.

@anemoijereja-eden
Copy link
Collaborator

potential architecture issue:
if the bot is restarted, then the scheduled task will be destroyed. we will need a way to ensure that the tasks are re-scheduled if the bot restarts, and it may be better to stick with polling for reminders that are far in the future to avoid bloating the task queue. Ideally a hybrid approach would be better, where we run polling at a decreased rate (maybe once every 12 hours) and register tasks for reminders that are <24h away that don't already have a task scheduled.

@anemoijereja-eden
Copy link
Collaborator

as this pull is still in progress and not ready for review/merge yert, I'm going to go ahead and convert it to a draft.

@anemoijereja-eden anemoijereja-eden marked this pull request as draft June 23, 2025 01:00
@anemoijereja-eden anemoijereja-eden self-assigned this Jun 23, 2025
@RainzDev
Copy link
Contributor Author

potential architecture issue:
if the bot is restarted, then the scheduled task will be destroyed. we will need a way to ensure that the tasks are re-scheduled if the bot restarts, and it may be better to stick with polling for reminders that are far in the future to avoid bloating the task queue. Ideally a hybrid approach would be better, where we run polling at a decreased rate (maybe once every 12 hours) and register tasks for reminders that are <24h away that don't already have a task scheduled.

Yes, that's why I mentioned about the on_ready part before. If a bot restarts, on_ready will loop through the database for reminders that haven't met the deadline yet. If there are reminders that aren't done, it'll continue to remind them on the updated time. If they were already meant to be reminded after the bot restart, it'll remind them instantly.

@RainzDev RainzDev marked this pull request as ready for review June 23, 2025 20:47
Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey @RainzDev - I've reviewed your changes and they look great!


Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

"""
return await self.find_unique(where={"reminder_id": reminder_id})

async def get_unsent_reminders(self) -> list[Reminder]:
Copy link
Collaborator

Choose a reason for hiding this comment

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

making changes to db and controller structure this close to a large migration is not advisable. is this necessary?

Copy link
Collaborator

@anemoijereja-eden anemoijereja-eden left a comment

Choose a reason for hiding this comment

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

Changes look great. passes all tests, and works fine in my local test instance.

@anemoijereja-eden anemoijereja-eden merged commit 5f8a00e into main Jun 23, 2025
36 checks passed
@anemoijereja-eden anemoijereja-eden deleted the remindme-revamp branch June 23, 2025 21:11
@sentry
Copy link

sentry bot commented Jul 4, 2025

Suspect Issues

This pull request was deployed and Sentry observed the following issues:

Did you find this useful? React with a 👍 or 👎

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.

3 participants