如何解决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
相关产品推荐
相关产品推荐

