You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 05:03:30