Telethon数据库锁定问题求助:消息发送软件报错排查
解决Telethon "database is locked" 错误
错误原因分析
你的代码存在两个核心问题导致数据库锁错误:
- 频繁创建/销毁TelegramClient实例:在
send_messages的循环中,每发送一条消息就新建一个TelegramClient、启动、断开。这种频繁操作会导致SQLite(Telethon会话的存储引擎)无法及时释放数据库文件锁,进而引发冲突。 - 异常处理变量未定义:
except UserPrivacyRestrictedError:块中使用了变量e但未声明,会导致额外报错,干扰正常流程。
修复方案
1. 复用TelegramClient实例
将Client的创建和启动移到循环外部,整个会话只初始化一次,循环结束后再统一断开连接,避免重复操作会话文件。
2. 修复异常处理逻辑
补充as e声明异常变量,确保错误信息能正常输出,同时可添加全局异常捕获覆盖更多场景。
3. 优化多线程异步循环
确保每个线程的异步循环独立运行并正确关闭,避免资源泄漏。
修改后的代码
async def send_messages(self, api_id, api_hash, session_name, usernames, message, delay, max_messages): messages_sent = 0 # 循环外创建并启动Client,复用实例 client = TelegramClient(f'sessions/{session_name}', api_id, api_hash) await client.start() try: for username in usernames: if messages_sent >= max_messages: break try: result = await client(ResolveUsernameRequest(username.strip())) user_id = result.peer.user_id await client.send_message(user_id, message) self.console_output.insert(tk.END, f'Successfully sent message to {username} using session {session_name}\n') messages_sent += 1 self.sent_usernames.add(username) await asyncio.sleep(delay) except UserPrivacyRestrictedError as e: self.console_output.insert(tk.END, f'Could not send message to {username}: {e}\n') except Exception as e: self.console_output.insert(tk.END, f'Error sending to {username}: {e}\n') await asyncio.sleep(delay) # 出错后延迟,避免频繁重试 finally: # 无论是否出错,最后统一断开Client await client.disconnect() # 多线程部分优化 session_files = [file for file in os.listdir('sessions') if file.endswith('.session')] if not session_files: self.console_output.insert(tk.END, "No session files found in the 'sessions' folder.\n") else: chunk_size = len(self.usernames) // len(session_files) for i, session_name in enumerate(session_files): start_index = i * chunk_size end_index = start_index + chunk_size if i < len(session_files) - 1 else len(self.usernames) chunk_usernames = self.usernames[start_index:end_index] # 封装循环启动逻辑,确保loop正确关闭 def run_async_task(): loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) loop.run_until_complete(self.send_messages(api_id, api_hash, session_name, chunk_usernames, message, delay, max_messages)) loop.close() self.sending_thread = threading.Thread(target=run_async_task) self.sending_thread.start()
额外建议
- 确保每个线程对应唯一的session文件,避免多线程同时操作同一个会话文件。
- 控制线程启动数量,避免一次性启动过多线程导致系统资源占用过高。
- 添加会话有效性检查,提前过滤过期或无效的session文件。
内容的提问来源于stack exchange,提问作者Adi Goldin
相关产品推荐
相关产品推荐

