From cc361158a4a5c2a42eebaeafa3ff3c6a8022aaec Mon Sep 17 00:00:00 2001 From: Nick Date: Tue, 7 May 2024 07:24:55 -0400 Subject: [PATCH] better loop --- DoorNotifier.Tests/WorkerTests.cs | 54 ++++++++++++++++--------------- DoorNotifier/WorkerService.cs | 34 +++++++++++++------ 2 files changed, 52 insertions(+), 36 deletions(-) diff --git a/DoorNotifier.Tests/WorkerTests.cs b/DoorNotifier.Tests/WorkerTests.cs index 1d415a6..a2a542c 100644 --- a/DoorNotifier.Tests/WorkerTests.cs +++ b/DoorNotifier.Tests/WorkerTests.cs @@ -38,12 +38,14 @@ public async Task ExecuteAsync_WhenDoorIsClosed_ShouldNotifyOnce() var once = true; _mockSensorClient .Setup(s => s.GetAsync()) - .Returns(() => { - if (once) { - once = false; - return Task.FromResult(SensorClient.OPEN); - } - return Task.FromResult(SensorClient.CLOSED); + .Returns(() => + { + if (once) + { + once = false; + return Task.FromResult(SensorClient.OPEN); + } + return Task.FromResult(SensorClient.CLOSED); }); @@ -57,28 +59,28 @@ public async Task ExecuteAsync_WhenDoorIsClosed_ShouldNotifyOnce() _mockNotifyClient.Verify(n => n.PostAsync(SensorClient.CLOSED), Times.Once); } - [Fact] - public async Task ExecuteAsync_WhenDoorIsOpened_ShouldNotifyEveryfter() - { - var worker = new WorkerService( - _fakeLogger, - _mockSensorClient.Object, - _mockNotifyClient.Object - ); + [Fact] + public async Task ExecuteAsync_WhenDoorIsOpened_ShouldNotifyEveryfter() + { + var worker = new WorkerService( + _fakeLogger, + _mockSensorClient.Object, + _mockNotifyClient.Object + ); - // Door starts open, and stays that way. - _mockSensorClient - .Setup(s => s.GetAsync()) - .ReturnsAsync(SensorClient.OPEN); + // Door starts open, and stays that way. + _mockSensorClient + .Setup(s => s.GetAsync()) + .ReturnsAsync(SensorClient.OPEN); - await worker.StartAsync(CancellationToken.None); - await Task.Delay(TimeSpan.FromSeconds(1)); - await worker.StopAsync(CancellationToken.None); + await worker.StartAsync(CancellationToken.None); + await Task.Delay(TimeSpan.FromSeconds(1)); + await worker.StopAsync(CancellationToken.None); - // Assert - // 7 is enough to cover 'After' - _mockSensorClient.Verify(s => s.GetAsync(), Times.AtLeast(7)); - _mockNotifyClient.Verify(n => n.PostAsync(SensorClient.OPEN), Times.AtLeast(2)); - } + // Assert + // 7 is enough to cover 'After' + _mockSensorClient.Verify(s => s.GetAsync(), Times.AtLeast(7)); + _mockNotifyClient.Verify(n => n.PostAsync(SensorClient.OPEN), Times.AtLeast(2)); + } } diff --git a/DoorNotifier/WorkerService.cs b/DoorNotifier/WorkerService.cs index 27f8da2..28a368d 100644 --- a/DoorNotifier/WorkerService.cs +++ b/DoorNotifier/WorkerService.cs @@ -8,6 +8,7 @@ public class WorkerService : BackgroundService private readonly ILogger _logger; private readonly ISensorClient _sensorClient; private readonly INotifyClient _notifyClient; + private readonly PeriodicTimer _timer; private bool _wasClosed; private DateTime _lastChange; @@ -21,6 +22,21 @@ INotifyClient notifyClient _logger = logger; _sensorClient = sensorClient; _notifyClient = notifyClient; + _timer = new PeriodicTimer(_sensorClient.Interval); + } + + public override void Dispose() + { + _timer.Dispose(); + base.Dispose(); + } + + private async Task SetInitialValuesAsync() + { + // Before going into the loop, load initial values. + var payload = await _sensorClient.GetAsync(); + _lastChange = DateTime.UtcNow; + _wasClosed = payload == SensorClient.CLOSED; } private async Task CheckDoorStateAsync() @@ -32,17 +48,19 @@ private async Task CheckDoorStateAsync() var isClosed = payload == SensorClient.CLOSED; var isChange = _wasClosed != isClosed; - if (isChange) { + if (isChange) + { _lastChange = now; _wasClosed = isClosed; // Notify on every change... _logger.LogDebug(LogEvent.DoorChanged, "Door state has changed to {Description}", payload); await _notifyClient.PostAsync(payload); - } + } var elapsed = now - _lastChange; _logger.LogInformation(LogEvent.DoorState, "Door state {Description} {Elapsed:g}", payload, elapsed); - if (!_wasClosed && elapsed > _notifyClient.After) { + if (!_wasClosed && elapsed > _notifyClient.After) + { // Notify again when it has been open for a while. _logger.LogDebug(LogEvent.DoorLeftOpen, "Door was left open"); // Restart the clock to notify again after another hour. @@ -56,15 +74,11 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken) _logger.LogInformation(LogEvent.PollingStarted, "Polling {Description:g}", _sensorClient.Interval); try { - // Before going into the loop, load initial values. - var payload = await _sensorClient.GetAsync(); - _lastChange = DateTime.UtcNow; - _wasClosed = payload == SensorClient.CLOSED; - - using var timer = new PeriodicTimer(_sensorClient.Interval); - while (await timer.WaitForNextTickAsync(stoppingToken)) + await SetInitialValuesAsync(); + while (!stoppingToken.IsCancellationRequested) { await CheckDoorStateAsync(); + await _timer.WaitForNextTickAsync(stoppingToken); } } catch (OperationCanceledException)