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

如何高效存储WTelegramClient的Saved Session以优化多用户API应用?

基于WTelegramClient的高效会话存储方案(适配Azure Redis Cache)

首先明确:不要直接在Redis中存储WTelegram.Client实例——这类带网络连接和运行状态的.NET对象无法可靠完成序列化/反序列化,Redis适合存储轻量的会话数据而非实例本身。我们可以利用WTelegramClient自带的会话持久化能力,将会话数据存储到Redis,从而复用会话、大幅降低Client初始化的资源消耗。

核心思路

  1. 以用户手机号为唯一标识,在Redis中存储对应Telegram会话的序列化数据
  2. 创建Client时优先从Redis加载已有会话,跳过重复登录流程
  3. 会话更新后(如登录成功、token自动刷新),自动同步最新会话数据到Redis
  4. 本地保留短期Client实例缓存,平衡Redis访问开销与内存占用

修改后的实现代码

假设使用StackExchange.Redis操作Azure Redis Cache,先安装对应NuGet包:StackExchange.Redis

using StackExchange.Redis;
using WTelegram;
using System.Text.Json;
using System.Collections.Concurrent;

namespace TelegramMicroservice.Services.Telegram
{
    public class WTelegramClientFactory : IWTelegramClientFactory
    {
        private const string ApiId = "你的API_ID";
        private const string ApiHash = "你的API_HASH";
        private readonly IDatabase _redisDb;
        private readonly ConcurrentDictionary<string, Client> _localClientCache = new();
        // 本地Client实例缓存过期时间(可根据业务调整)
        private readonly TimeSpan _localCacheExpiry = TimeSpan.FromMinutes(30);

        public WTelegramClientFactory(IConnectionMultiplexer redisMultiplexer)
        {
            _redisDb = redisMultiplexer.GetDatabase();
            // 后台定期清理本地过期的Client实例
            _ = Task.Run(CleanupLocalCacheAsync);
        }

        public Client GetOrCreateClient(string phoneNumber)
        {
            // 先查本地缓存
            if (_localClientCache.TryGetValue(phoneNumber, out var client))
                return client;

            // 本地无缓存则从Redis加载会话
            var sessionJson = _redisDb.StringGet(GetRedisSessionKey(phoneNumber));
            Client newClient;

            if (!sessionJson.IsNullOrEmpty)
            {
                // 反序列化Redis中的会话数据
                var savedSession = JsonSerializer.Deserialize<Client.Session>(sessionJson);
                newClient = new Client(ConfigCallback, savedSession);
            }
            else
            {
                // 无历史会话,创建新Client
                newClient = new Client(ConfigCallback);
            }

            // 监听会话变更事件,自动同步到Redis
            newClient.SessionChanged += async (_, args) =>
            {
                var serializedSession = JsonSerializer.Serialize(args.Session);
                await _redisDb.StringSetAsync(GetRedisSessionKey(phoneNumber), serializedSession, TimeSpan.FromDays(7));
            };

            // 将新Client加入本地缓存
            _localClientCache.TryAdd(phoneNumber, newClient);
            return newClient;
        }

        private string ConfigCallback(string configKey)
        {
            return configKey switch
            {
                "api_id" => ApiId,
                "api_hash" => ApiHash,
                "phone_number" => null, // 会话已包含登录信息,无需重复提供
                _ => null,
            };
        }

        private string GetRedisSessionKey(string phoneNumber) => $"telegram:session:{phoneNumber}";

        private async Task CleanupLocalCacheAsync()
        {
            while (true)
            {
                await Task.Delay(TimeSpan.FromMinutes(10));
                // 可扩展Client类添加LastUsedTime属性,判断实例是否闲置
                // 示例逻辑:移除超过缓存过期时间的闲置实例
                foreach (var phone in _localClientCache.Keys.ToList())
                {
                    // if (_localClientCache[phone].LastUsedTime < DateTime.UtcNow - _localCacheExpiry)
                    //     _localClientCache.TryRemove(phone, out _);
                }
            }
        }
    }
}

关键优化点

  • 自动会话同步:利用WTelegramClient的SessionChanged事件,无需手动维护会话状态,更新自动同步到Redis
  • 分层缓存架构:本地短期缓存减少Redis访问频次,Redis存储长期会话数据,兼顾性能与分布式场景一致性
  • 安全防护:建议对Redis中的会话数据进行加密(如AES),避免敏感登录信息泄露
  • 资源回收机制:后台定期清理本地闲置Client实例,防止内存占用过高

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 16:00:32