首页 > 解决方案 > System.Threading.Timer:在此上下文中启动了第二个操作

问题描述

我在 .NET 5 上有控制台应用程序,它是 Discord Bot。在启动应用程序时,我遇到了这个问题:

System.InvalidOperationException:在前一个操作完成之前,在此上下文上启动了第二个操作。这通常是由不同的线程同时使用同一个 DbContext 实例引起的。有关如何避免 DbContext 线程问题的更多信息

这发生在 Timer

这是在构造函数中:

_approveTimer = new Timer(async delegate
            {
                await CheckApproveAsync();
            }, null, TimeSpan.Zero,
                TimeSpan.FromSeconds(30));
public async Task CheckApproveAsync()
{
    var pendingUsers = await _pendingUsers.GetAllAsync();

    if (pendingUsers is null || !pendingUsers.Any())
        return;

    Program.Log.Debug($"Checking {pendingUsers.Count} pending users...");

    foreach (var user in pendingUsers)
    {
        var expired = DateTime.UtcNow > user.ExpirationTime;

        if (!expired) continue;

        await _pendingUsers.DeleteWithDetachAsync(user);
        IonicHelper.GetGuildUserById(_mainGuildId, user.UserId, out var sgUser);

        try
        {
            var msg = await _messageService.GetMessageAsync("register-pending-expired", new FormatData(user.UserId));
            await sgUser.SendIonicMessageAsync(msg);
        }
        catch (Exception ex)
        {
            await _serverHelper.SendLogAsync(_mainGuildId, "Error", $"{nameof(CheckApproveAsync)} - {ex.Message}");
        }
    }

    var usersValidated = 0;

    foreach (var user in pendingUsers)
    {
        RequestResult codeResult;
        string code;
        try
        {
            (codeResult, code) = await GetThirdPartyCodeByEncryptedSummonerIdAsync(user.Region, user.SummonerId);
        }
        catch (Exception)
        {
            continue;
        }

        if (code is null || codeResult != RequestResult.Success)
            continue;

        var sanitizedCode = new string(code.Where(char.IsLetterOrDigit).ToArray());

        if (sanitizedCode != user.ConfirmationCode)
            continue;

        var (requestResult, summoner) = await GetSummonerByEncryptedPuuIdAsync(user.Region, user.PlayerUUID);

        if (requestResult != RequestResult.Success)
        {
            await _pendingUsers.DeleteWithDetachAsync(user);
            continue;
        }

        var (rankResult, rankData) = await GetLeaguePositionsByEncryptedSummonerIdAsync(user.Region, summoner.Id);

        var soloqRank = GetRankModelFromEntry(rankData.FirstOrDefault(x => x.QueueType == "RANKED_SOLO_5x5"));

        var summonerIcon = GetSummonerIconUrlById(summoner.ProfileIconId);

        var lolData = new LeagueData
        {
            UserId = user.UserId,
            SummonerRegion = user.Region,
            PlayerUUID = summoner.Puuid,
            AccountId = summoner.AccountId,
            SummonerId = summoner.Id,
            SummonerName = summoner.Name,
            SummonerIcon = summonerIcon,
            SummonerLevel = summoner.SummonerLevel,
            SummonerRank = $"{soloqRank.Tier} {soloqRank.Rank}"
        };

        _ = IonicHelper.GetGuildUserById(_mainGuildId, user.UserId, out var sgUser);

        await AssignRoleFromRankAsync(sgUser, soloqRank.Tier);

        var data = await _leagueRepository.GetByIdAsync(user.UserId);

        if (data == null)
        {
            await _leagueRepository.AddAsync(lolData);
        }

        usersValidated++;

        user.SummonerName = lolData.SummonerName;

        await PostValidateAsync(user);
    }

    Program.Log.Information($"{usersValidated} users validated.");
}

我读到如果不等待某些方法可能是个问题,但我已经检查过它是否都在等待。对此有何建议?

标签: timerentity-framework-core.net-5

解决方案


推荐阅读