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

Telegram Bot无法检测用户退出事件的技术求助

Telegram Bot退群事件检测异常问题

基本信息

使用Python 3.11.0和python-telegram-bot==21.5,通过Redis存储数据。

Bot核心功能:为每个新加入群组的用户设置10分钟计时器,到期自动踢出用户;若用户在计时器到期前主动退群,计时器暂停,再次入群时从上次剩余时间继续计时(比如初始10分钟,退群时剩4分钟,再次入群就设4分钟计时器)。

问题现象

用自己的小号测试(加入、退群、再次加入)时功能正常,但在大群或其他用户操作时失效:Bot无法检测到用户退群事件,退群分支的日志从未输出。用户再次入群时,Redis中没有存储该用户的left时间,导致left_time为None,执行datetime.fromisoformat(left_time)时触发错误。

日志示例

INFO:apscheduler.scheduler:Removed job 9065c10968444e8dba41593926032c99
INFO:__main__: Join Time: 2025-01-04T08:25:38.461033+00:00 +++++++ Left Time: None
ERROR:__main__:There has been an error: fromisoformat: argument must be str
INFO:apscheduler.scheduler:Added job "<JOB_NAME>" to job store "default"

相关代码

def memberJoin(chatMemberUpdate: ChatMemberUpdated):
    status = chatMemberUpdate.difference().get("status")
    old, new = status or (None, status)

    if old in (None, ChatMember.BANNED, ChatMember.LEFT) and new == ChatMember.MEMBER:
        return True
    
    return False

def memberLeft(chatMemberUpdate: ChatMemberUpdated):
    status = chatMemberUpdate.difference().get("status")
    old, new = status or (None, status)

    if old == ChatMember.MEMBER and new == ChatMember.LEFT:
        return True
    
    return False

async def check_status(update: Update, context: ContextTypes.DEFAULT_TYPE):
    left = memberLeft(update.chat_member)
    join = memberJoin(update.chat_member)
    user_id = update.chat_member.from_user.id
    chat_id = update.chat_member.chat.id

    if join:
        # 首次入群
        if not memory.hexists(user_id, "join"):
            memory.hset(user_id, "join", datetime.now().isoformat())
            
            # 计时器相关逻辑...

         else:
            # 计时器到期前再次入群
            memory.persist(user_id)
            join_time = memory.hget(user_id, "join")
            left_time = memory.hget(user_id, "left")

            logger.info(f"Join Time: {join_time} +++++++ Left Time: {left_time}")

            elapsed_time = (datetime.fromisoformat(left_time) - datetime.fromisoformat(join_time)).total_seconds()
            remaining_time = 10 * 60 - elapsed_time # 剩余计时时间
            
            if remaining_time > 0:
                # 重新设置计时器相关逻辑...


    elif left:
        logger.info(f"User {user_id} left at {datetime.now().isoformat()}.")
        memory.hset(user_id, "left", datetime.now().isoformat())
        memory.expire(user_id, timedelta(hours = 1))
        
        # 停止之前的计时器相关逻辑...
        
if __name__ == "__main__":

    app = ApplicationBuilder().token(API_KEY).build()

    app.add_handler(ChatMemberHandler(check_status, ChatMemberHandler.CHAT_MEMBER))
    
    app.run_polling(drop_pending_updates = True, allowed_updates = Update.ALL_TYPES)

更新

调试发现群组内还有另一个Bot在踢人,这干扰了测试结果,但不是核心问题。另外,重启Docker容器时JobQueue被取消,但Redis中残留了旧的用户ID,可能引发部分异常。目前功能看似恢复正常,已能看到退群日志:

INFO:__main__: User <USER_ID> left at 2025-01-04T18:05:55.069938+00:00.

内容的提问来源于stack exchange,提问作者Leah

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 06:15:08