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

为什么单实例Discord.Net程序有时会重复执行同一段代码?

根因定位

你的问题核心是Discord库的重连机制触发了重复的Ready事件,而你将游戏调度的初始化逻辑放在了Ready事件回调中,每次重连都会新增一个独立的等待任务,多个任务同时倒计时结束后就会重复调用StartNewGame。闲置时网络波动触发重连的概率更高,符合你观察到的闲置后复现、重启后暂时消失的特征。

排查验证步骤

  • 在Ready事件入口加日志,输出触发时间和线程ID,确认每次重连时是不是多次触发了该事件
  • 检查调度逻辑的取消机制:原有逻辑里的Task.Delay没有绑定取消令牌,重连后旧的等待任务不会被销毁,会一直运行到倒计时结束
  • 确认你使用的是全局共享的MySql连接对象,多线程同时操作时自然会触发DataReader占用的崩溃问题

解决方案

1. 调度逻辑加去重取消机制

全局定义取消令牌源,每次触发Ready事件时先销毁旧的等待任务,再启动新的调度,避免多任务残留:

// 全局定义
private static CancellationTokenSource _gameScheduleCts = new CancellationTokenSource();

// Ready事件回调中的调度逻辑替换为以下代码
// 先取消旧的调度任务
_gameScheduleCts.Cancel();
_gameScheduleCts = new CancellationTokenSource();
var currentToken = _gameScheduleCts.Token;

DateTime deadline = Convert.ToDateTime(dt.Rows[0][0]);
int ms = (int)(deadline - DateTime.Now).TotalMilliseconds;
if (ms > 0)
{
     Console.WriteLine("Waiting until " + deadline.ToLongTimeString() + " to start a new game.");
     try
     {
         await Task.Delay(ms, currentToken);
     }
     catch (TaskCanceledException)
     {
         // 任务被取消直接退出,不执行后续逻辑
         return;
     }
}
// 执行前再判断一次令牌状态,避免极端情况的并发
if (!currentToken.IsCancellationRequested)
{
    await StartNewGame("All Any", false, false);
}

2. 修正数据库连接使用方式

不要使用全局共享的MySql连接,ADO.NET自带连接池,每次操作单独开连接即可,完全避免多线程访问冲突,还能解决DataReader崩溃的问题:

// 将StartNewGame中的数据库操作替换为以下写法
cmdText = string.Format("update servers set deadline = '{0}' where serverid = '{1}'", newtry.ToString("yyyy-MM-dd HH:mm:ss"), _bot.server.Id);
using (var conn = new MySqlConnection(你的数据库连接字符串))
{
    await conn.OpenAsync();
    using (var cmd = new MySqlCommand(cmdText, conn))
    {
        await cmd.ExecuteNonQueryAsync();
    }
}

3. 加最终兜底互斥逻辑

就算前面的逻辑出问题,也保证StartNewGame同一时间只能运行一个实例:

// 全局定义锁对象
private static readonly SemaphoreSlim _startGameSemaphore = new SemaphoreSlim(1, 1);

public async Task StartNewGame(string type, bool forced, bool speed, List<ulong> players = null)
{
    // 尝试获取锁,获取失败直接返回,避免重复执行
    if (!await _startGameSemaphore.WaitAsync(0))
    {
        return;
    }
    try
    {
        // 原有方法逻辑
    }
    finally
    {
        _startGameSemaphore.Release();
    }
}

4. 优化Discord库重连配置

如果你使用的是Discord.NET库,检查以下配置减少不必要的重连:

  • 开启所有需要的GatewayIntents,避免因为权限不足被服务端断开连接
  • 配置AlwaysDownloadUsers = true减少首次连接时的超时概率
  • 调整连接超时参数,避免弱网环境下频繁重连

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.09 13:00:02