【问题标题】:Noda Time and recurrent operations (c#)野田时间和循环操作(c#)
【发布时间】:2020-10-18 12:45:23
【问题描述】:

我正在尝试编写一个“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", baseUri, Endpoint);
    }
}

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

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

   await _clock.Delay(...);

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

你知道一些优雅的方式来实现这种行为吗?

【问题讨论】:

    标签: c# timer delay nodatime


    【解决方案1】:

    IClock 没有任何延迟的概念 - 它回答“现在几点了”的问题。

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

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

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

    当然,您可能有更简单的要求 - 如果您没有其他事情要做,您可能只是能够提前时钟。但请注意其局限性,因为其他异步操作不会同时发生。

    这里的基本思想非常有用 - 但实施起来确实很麻烦。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-01-28
      • 1970-01-01
      • 2014-09-20
      • 2014-10-22
      • 1970-01-01
      • 1970-01-01
      • 2012-06-01
      相关资源
      最近更新 更多