DragonBot Ticket Close Hang

Context DragonBot is a customer-support ticket bot for a purchasing-agent business on Discord, written with discord.py. A customer opens a ticket, which is a private channel visible only to the customer and staff. Every status change renames the channel to {type}-{id:04d}-{status}, so staff can see the status from the channel list. Closing a ticket sets the status to CLOSED, exports the conversation with DiscordChatExporter, posts the transcript to an archive channel, and DMs the customer a feedback form. What Happened After a staff member confirmed closing a ticket, the bot sometimes sat on 「正在生成頻道紀錄以及傳送回饋單給顧客…」 for up to 10 minutes before the after-close buttons appeared. The owner reported it too. ...

October 10, 2026 · 4 min · xDDoubleTea

LeetCodeBot: One Session, Many Commands

Context LeetCodeBot talks to its database through AsyncDatabaseManager, an async context manager that hands out SQLAlchemy sessions: async with self.async_database_manager as db: db.add(row) # leaving the block commits, or rolls back on error main.py creates one manager and shares it across every cog. The old version looked like this: async def __aenter__(self) -> AsyncSession: self.session = self._sessionmaker() return self.session async def __aexit__(self, exc_type, exc_val, exc_tb): try: assert self.session if exc_type: await self.session.rollback() else: await self.session.commit() await self.session.close() except AssertionError: return True finally: return False It has two bugs (#38). Bug 1: __aexit__ commits the wrong session __aenter__ returns a new session, so the caller’s db is bound to that object. But __aexit__ reads self.session, which belongs to the shared manager. ...

August 28, 2026 · 5 min · xDDoubleTea

LeetCodeBot: The Bug the Async Migration Did Not Write

Context LeetCodeBot is a Discord bot for looking up and discussing LeetCode problems. It stores problems and their topic tags with SQLAlchemy on SQLite. In August 2026, #35 moved the database layer from synchronous SQLAlchemy to async (sqlite+aiosqlite). The bot kept running in production afterwards, with no errors. What happened A fresh clone could not start the bot. Deleting the database file to “start clean” made it fail every time: sqlalchemy.exc.MissingGreenlet: greenlet_spawn has not been called; can't call await_only() here. Was IO attempted in an unexpected place? File "core/leetcode_problem.py", line 420, in add_problem_to_db if db_tag not in db_problem.tags: The failing expression is a plain attribute read: db_problem.tags. ...

August 28, 2026 · 4 min · xDDoubleTea