Noda时间和循环操作C#

问题描述

我正在尝试编写“ ping”代码,每分钟一次将其发布到某些休息服务。

我最简单的“旧”方法将是:

while (true)
{
    if (cancellationToken.IsCancellationRequested)
    {
        return;
    }

    await Task.Delay(TimeSpan.FromMinutes(1),cancellationToken);

    try
    {
        await PingImpl(clientId,baseUri,cancellationToken);
    }
    catch (Exception ex)
    {
        _logger.LogError(ex,"ping {BaseUri} {Endpoint} failed",Endpoint);
    }
}

现在,要对重复调用服务器进行单元测试,我通常将延迟持续时间注入生产中的毫秒数和生产中的分钟数(我知道它会每分钟轮询一次“较慢”,因为执行请求所需的时间,这是可以接受的)

现在,使用#codatime,我希望不要弄乱注入参数,并希望对IClock进行一些扩展,例如

   await _clock.Delay(...);

然后,单元测试代码将提前假时钟并触发操作。

您知道实现这种行为的一些优雅方法吗?

解决方法

IClock没有任何延迟的概念-仅 回答“当前时间是什么”的问题。

您想要的是不同的抽象。在我作为Google Cloud客户端库一部分维护的GAX项目中,我们有this abstraction

public interface IScheduler
{
    Task Delay(TimeSpan delay,CancellationToken cancellationToken);
}

就像IClock一样,有一个使用Task.Delay的单例实现-和test implementation可以提前一个时钟。我要说的是,随着时间的流逝,测试实现给我们带来了很多问题,因为这是一件非常复杂的事情。您不能只是提前时钟然后返回已完成的任务-因为您希望在启动和完成延迟之间的“模拟时间内”发生其他异步调用。

您当然可能有更简单的要求-如果您没有其他事情要做,您也许可以提前进行。但是要意识到这一点的局限性,因为与此同时没有发生其他异步操作。

这里的基本想法是一个非常有用的想法-但实现起来确实很麻烦。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...