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

如何解决ASP.NET Core 3.1 Worker Service定时任务仅执行一次的问题

问题根因与修复方案

核心问题&需修复点

  • 你当前的ExecuteAsync方法没有循环包裹业务逻辑,仅会执行一次就结束,所以只会发送1次短信
  • SendingSMSService的sendSMS方法使用了async void且混用.Result,存在死锁风险,且调用时没有await,可能导致请求未完成就被资源释放
  • 服务作用域(Scope)位置错误,单次执行后就被释放,后续无法正常获取服务
  • 定时延迟当前设置为120000ms(2分钟),不是你预期的5秒
  • 缺少异常捕获,单次执行报错后会直接终止服务

修改后的代码

Worker类

public class Worker : BackgroundService, IHostedService, ISendingSMS
{
    public IServiceScopeFactory _serviceScopeFactory;
    public Report report { get; set; }

    public Worker(IServiceScopeFactory serviceScopeFactory)
    {
        _serviceScopeFactory = serviceScopeFactory;
    }

    public async Task GetReport(MarketsContext context)
    {
        report = await context.Report.Select(x => new Report
        {
            ReportDate = x.ReportDate,
            TotalMarkets = x.TotalMarkets,
        }).AsNoTracking().FirstOrDefaultAsync();
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        // 新增while循环,服务未停止就持续执行
        while (!stoppingToken.IsCancellationRequested)
        {
            try
            {
                // 每次执行新建Scope,避免服务生命周期问题
                using (var scope = _serviceScopeFactory.CreateScope())
                {
                    var dbContext = scope.ServiceProvider.GetRequiredService<MarketsContext>();
                    var _smssend = scope.ServiceProvider.GetRequiredService<SendingSMSService>();

                    await GetReport(dbContext);

                    var message = new MsgContent
                    {
                        Username = "cse.etsg",
                        Password = "wrwe",
                        From = "4500000",
                        To = "+429124203243",
                        Message = $"{report.ReportDate} {report.TotalMarkets}"
                    };

                    // 异步等待短信发送完成
                    await _smssend.sendSMS(message);
                }
            }
            catch (Exception ex)
            {
                // 此处可添加日志记录错误,避免单次报错终止整个服务
            }
            // 改为5秒延迟,对应你预期的执行间隔
            await Task.Delay(5000, stoppingToken);
        }
    }

    public override async Task StartAsync(CancellationToken cancellationToken)
    {
        await base.StartAsync(cancellationToken);
    }

    public override async Task StopAsync(CancellationToken cancellationToken)
    {
        await base.StopAsync(cancellationToken);
    }
}

SendingSMSService类

public class SendingSMSService
{
    public Report report { get; set; }

    // 改为返回Task,去掉.Result改用await
    public async Task sendSMS(MsgContent message)
    {
        using (var client = new HttpClient())
        {
            var myContent = JsonConvert.SerializeObject(message);
            var buffer = System.Text.Encoding.UTF8.GetBytes(myContent);
            var byteContent = new ByteArrayContent(buffer);
            byteContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");

            using (var result = await client.PostAsync("https://api/SendSMS", byteContent))
            {
                string Response = await result.Content.ReadAsStringAsync();
                // 可在这里添加响应结果校验、日志记录逻辑
            }
        }
    }
}

优化建议

  • 建议注入IHttpClientFactory来创建HttpClient,避免频繁创建释放HttpClient导致的端口占用问题
  • 可以将短信接口配置、定时间隔这些参数放到配置文件中,不要硬编码在代码里
  • 补充日志输出,方便排查执行过程中的异常问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.22 03:54:06