如何解决BackgroundService 计时器中的存储过程
我想要一个使用 .net core 3.0 运行 evrey 5 秒的存储过程。
我一直在使用 BackgroundService,当我尝试调用存储过程时,我得到“线程 0xcec 已退出并带有代码”
{
public class ImportScope : BackgroundService
{
private readonly BlockContext _context;
private readonly ILogger<ImportScope> _logger;
private Timer timer;
private readonly IServiceScopeFactory _scopeFactory;
public ImportScope(ILogger<ImportScope> logger,IServiceScopeFactory scopeFactory)
{
_logger = logger;
_scopeFactory = scopeFactory;
}
protected override Task ExecuteAsync(CancellationToken stoppingToken)
{
var scope = _scopeFactory.CreateScope();
var blockContext = scope.ServiceProvider.GetrequiredService<BlockContext>();
timer = new Timer(o => blockContext.CourseExtentions.FromsqlRaw("exec stored_proc_wanted")),null,TimeSpan.Zero,TimeSpan.FromSeconds(5));
return Task.CompletedTask;
}
}
}
解决方法
没有看到您的 Timer 实现,我猜第一个参数是您要执行的表达式。首先要考虑的是 DbContext 不是线程安全的,因此它们应该在它们正在执行的线程中进行实例化和处理。
为了可读性,我会为存储过程的执行创建一个函数,包括 DbContext 的范围:
private void execSproc()
{
using (var scope = _scopeFactory.CreateScope())
{
using (var blockContext = scope.ServiceProvider.GetRequiredService<BlockContext>())
{
blockContext.CourseExtentions.FromSqlRaw("exec stored_proc_wanted");
}
}
}
然后在您的计时器任务方法中:
protected override Task ExecuteAsync(CancellationToken stoppingToken)
{
timer = new Timer(o => execSproc,null,TimeSpan.Zero,TimeSpan.FromSeconds(5));
return Task.CompletedTask;
}
这是假设您的 Scope 正在实现 IDisposable,大多数 DbContextScope/工作单元模式应该是这样。最终,DbContext 需要在计时器任务上启动的线程内限定范围。我不确定 Task.CompletedTask
与计时器相关的含义是什么。
我还建议删除:
private readonly BlockContext _context;
因为如果模式要使用 ContextScope / UoW (IServiceScopeFactory
),这不是注入成员,所以此模式的目的是提供围绕 DbContext 的范围,因此您不应该一直挂在对 DbContext 的引用。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。