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

使用MadelineProto获取Telegram多个会话消息无返回问题求助

问题根源分析
  • 异步模式无返回:MadelineProto的异步基于AMP协程框架,你定义的getMessagesById是生成器函数,直接调用不会触发执行,必须将协程挂载到事件循环中调度才会运行。
  • 同步模式仅单会话返回:你在getMessagesById中写了死循环while(true),第一个会话的调用进入循环后会一直阻塞,永远不会执行后续两个会话的调用逻辑。
  • ajax轮询返回空:每次ajax请求都会重新初始化MadelineProto实例,会话文件序列化/反序列化存在锁机制,频繁启动进程会导致读取会话失败;同时你每次拉取都从offset_id=0开始,无新消息时自然返回空结果。
修复方案

异步模式最优实现(支持多会话并行拉取)

异步模式是MadelineProto官方推荐的生产环境使用方式,可实现多会话并行拉取无阻塞:

<?php
require 'vendor/autoload.php';

use Amp\Promise;

$settings['logger']['logger'] = 0;
$settings['serialization']['serialization_interval'] = 30;
$MadelineProto = new \danog\MadelineProto\API('session.madeline', $settings);
$MadelineProto->async(true);
$MadelineProto->start();

$chatList = [1234567, 3254682, 154789965];

function getMessagesById(int $u_id, \danog\MadelineProto\API $MadelineProto): \Generator
{
    $offset_id = 0;
    $limit = 100;
    do {
        // 先转换为标准InputPeer格式,避免ID类型不匹配导致拉取失败
        $peer = yield $MadelineProto->getInfo($u_id)['InputPeer'];
        $messages_Messages = yield $MadelineProto->messages->getHistory([
            'peer' => $peer,
            'offset_id' => $offset_id,
            'offset_date' => 0,
            'add_offset' => 0,
            'limit' => $limit,
            'max_id' => 0,
            'min_id' => 0,
            'hash' => 0
        ]);

        if (count($messages_Messages['messages']) == 0) {
            break;
        }
        
        print_r($messages_Messages);

        $offset_id = end($messages_Messages['messages'])['id'];
        // 拉取完所有历史消息后自动终止,增量拉取可配合更新钩子实现
        if (count($messages_Messages['messages']) < $limit) {
            break;
        }
        
        yield $MadelineProto->sleep(3);
    } while (true);
}

// 将多个会话的拉取协程合并,挂载到事件循环执行
$MadelineProto->loop(function () use ($chatList, $MadelineProto) {
    $promises = [];
    foreach ($chatList as $chatId) {
        $promises[] = \Amp\call(fn() => getMessagesById($chatId, $MadelineProto));
    }
    yield Promise\all($promises);
});

异步方案说明

  • 多会话拉取并行执行,效率远高于同步模式
  • 新增InputPeer格式转换,兼容用户ID、群组ID、频道ID等多种peer类型,避免拉取失败
  • 移除无意义的死循环,如需增量拉取可配合MadelineProto的setUpdateHandler更新钩子实现,无需轮询

同步模式适配修改

如果必须使用同步模式,修改死循环逻辑即可支持多会话顺序拉取:

<?php
require 'vendor/autoload.php';

$settings['logger']['logger'] = 0;
$settings['serialization']['serialization_interval'] = 30;
$MadelineProto = new \danog\MadelineProto\API('session.madeline', $settings);
$MadelineProto->async(false);
$MadelineProto->start();

$chatList = [1234567, 3254682, 154789965];

function getMessagesById(int $u_id, \danog\MadelineProto\API $MadelineProto): void
{
    $offset_id = 0;
    $limit = 100;
    do {
        $peer = $MadelineProto->getInfo($u_id)['InputPeer'];
        $messages_Messages = $MadelineProto->messages->getHistory([
            'peer' => $peer,
            'offset_id' => $offset_id,
            'offset_date' => 0,
            'add_offset' => 0,
            'limit' => $limit,
            'max_id' => 0,
            'min_id' => 0,
            'hash' => 0
        ]);

        if (count($messages_Messages['messages']) == 0) {
            break;
        }
        
        print_r($messages_Messages);

        $offset_id = end($messages_Messages['messages'])['id'];
        if (count($messages_Messages['messages']) < $limit) {
            break;
        }
        
        sleep(3);
    } while (true);
}

// 循环调用多个会话拉取
foreach ($chatList as $chatId) {
    getMessagesById($chatId, $MadelineProto);
}

轮询场景优化建议

  • 不要通过ajax频繁启动新进程拉取消息,改为使用长驻进程运行MadelineProto,通过setUpdateHandler监听新消息,将消息存入数据库/缓存,ajax直接从缓存读数据,可完全避免空返回问题
  • 如果必须使用轮询,将每个会话的最新offset_id存入缓存,下次拉取时传入缓存的offset,仅拉取更新的消息,减少无效请求
  • 增加会话文件锁判断,避免多个进程同时读写同一个session.madeline文件导致读取失败

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.09 22:06:02