Skip to content

Commit

Permalink
Merge pull request #7 from prom-client-net/feat/default-interval
Browse files Browse the repository at this point in the history
feat: add default interval
  • Loading branch information
phnx47 authored Aug 19, 2023
2 parents b746499 + 3e6754b commit 1db780d
Show file tree
Hide file tree
Showing 8 changed files with 111 additions and 56 deletions.
1 change: 1 addition & 0 deletions .ruleset
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@
<Rule Id="SA1400" Action="None" />
<Rule Id="SA1401" Action="None" />
<Rule Id="SA1119" Action="None" />
<Rule Id="SA1407" Action="None" />
<Rule Id="SA1410" Action="None" />
<Rule Id="SA1411" Action="None" />
<Rule Id="SA1404" Action="None" />
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ var metricPusher = new MetricPusher(new MetricPusherOptions
```

```c#
services.AddMetricPusherService(metricPusher, TimeSpan.FromSeconds(1));
services.AddMetricPusherService(metricPusher);
```

## Contribute
Expand Down
8 changes: 8 additions & 0 deletions src/Defaults.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using System;

namespace Prometheus.Client.MetricPusher.HostedService;

internal static class Defaults
{
internal static TimeSpan Interval = TimeSpan.FromMilliseconds(1000);
}
30 changes: 18 additions & 12 deletions src/MetricPusherService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,39 +10,45 @@ public class MetricPusherService : BackgroundService
private readonly IMetricPusher _pusher;
private readonly TimeSpan _interval;

public MetricPusherService(IMetricPusher pusher)
: this(pusher, Defaults.Interval)
{
}

public MetricPusherService(IMetricPusher pusher, TimeSpan interval)
{
_interval = interval;
_pusher = pusher;
_interval = interval;
}

protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
async Task DoPushAsync()
while (!stoppingToken.IsCancellationRequested)
{
await DoPushAsync();
try
{
await _pusher.PushAsync();
await Task.Delay(_interval, stoppingToken);
}
catch (Exception)
catch (TaskCanceledException)
{
// TODO: report error to DiagnosticSource?
}
}

while (!stoppingToken.IsCancellationRequested)
// Push the very last metric values before exit
await DoPushAsync();
return;

async Task DoPushAsync()
{
await DoPushAsync();
try
{
await Task.Delay(_interval, stoppingToken);
await _pusher.PushAsync();
}
catch (TaskCanceledException)
catch (Exception)
{
// TODO: report error to DiagnosticSource?
}
}

// Push the very last metric values before exit
await DoPushAsync();
}
}
2 changes: 1 addition & 1 deletion src/Prometheus.Client.MetricPusher.HostedService.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.1;net6.0;net7.0</TargetFrameworks>
<VersionPrefix>0.1.0</VersionPrefix>
<VersionPrefix>0.2.0</VersionPrefix>
<Description>Prometheus.Client.MetricPusher as HostedService</Description>
<RepositoryUrl>https://github.com/prom-client-net/prom-client-metricpusher-hostedservice</RepositoryUrl>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
Expand Down
5 changes: 5 additions & 0 deletions src/ServiceCollectionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ namespace Prometheus.Client.MetricPusher.HostedService;

public static class ServiceCollectionExtensions
{
public static IServiceCollection AddMetricPusherService(this IServiceCollection services, IMetricPusher pusher)
{
return AddMetricPusherService(services, pusher, Defaults.Interval);
}

public static IServiceCollection AddMetricPusherService(this IServiceCollection services, IMetricPusher pusher, TimeSpan interval)
{
if (pusher == null)
Expand Down
53 changes: 38 additions & 15 deletions tests/MetricPusherServiceTests.cs
Original file line number Diff line number Diff line change
@@ -1,22 +1,45 @@
using System.Threading;
using System.Threading.Tasks;

namespace Prometheus.Client.MetricPusher.HostedService.Tests
namespace Prometheus.Client.MetricPusher.HostedService.Tests;

public class MetricPusherServiceTests
{
public class MetricPusherServiceTests
[Fact]
public async Task WithDefaultInterval_PushMetricPeriodically()
{
var metricPusherMock = Substitute.For<IMetricPusher>();
var metricPusherService = new MetricPusherService(metricPusherMock);
var canellationToken = Arg.Any<CancellationToken>();

await metricPusherService.StartAsync(canellationToken);
await Task.Delay(GetDelay(1), canellationToken);
await metricPusherService.StopAsync(canellationToken);

await metricPusherMock.Received(3).PushAsync();
}

[Theory]
[InlineData(1)]
[InlineData(2)]
[InlineData(3)]
[InlineData(5)]
public async Task WithGivenInterval_PushMetricPeriodically(int seconds)
{
var metricPusherMock = Substitute.For<IMetricPusher>();
var metricPusherService = new MetricPusherService(metricPusherMock, TimeSpan.FromSeconds(seconds));
var canellationToken = Arg.Any<CancellationToken>();

await metricPusherService.StartAsync(canellationToken);
await Task.Delay(GetDelay(seconds), canellationToken);
await metricPusherService.StopAsync(canellationToken);

await metricPusherMock.Received(3).PushAsync();
}

private static TimeSpan GetDelay(int seconds)
{
[Fact]
public async Task WithGivenInterval_PushMetricPeriodically()
{
var metricPusherMock = Substitute.For<IMetricPusher>();
var metricPusherService = new MetricPusherService(metricPusherMock, TimeSpan.FromSeconds(1));
var canellationToken = Arg.Any<CancellationToken>();

await metricPusherService.StartAsync(canellationToken);
await Task.Delay(TimeSpan.FromSeconds(1), canellationToken);
await metricPusherService.StopAsync(canellationToken);

await metricPusherMock.Received(3).PushAsync();
}
var milliseconds = seconds * 1000 + 100;
return TimeSpan.FromMilliseconds(milliseconds);
}
}
66 changes: 39 additions & 27 deletions tests/ServiceCollecttionExtensionsTests.cs
Original file line number Diff line number Diff line change
@@ -1,42 +1,54 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace Prometheus.Client.MetricPusher.HostedService.Tests
namespace Prometheus.Client.MetricPusher.HostedService.Tests;

public class ServiceCollecttionExtensionsTests
{
public class ServiceCollecttionExtensionsTests
[Fact]
public void AddMetricPusherService_WithNullMetricPusher_ThrowsArgumentNullException()
{
var servicesCollection = Substitute.For<IServiceCollection>();

Action act = () => servicesCollection.AddMetricPusherService(null, TimeSpan.FromSeconds(1));

act.Should().Throw<ArgumentNullException>();
}

[Fact]
public void AddMetricPusherService_WithZeroTimeInterval_ThrowsArgumentOutOfRangeException()
{
[Fact]
public void AddMetricPusherService_WithNullMetricPusher_ThrowsArgumentNullException()
{
var servicesCollection = Substitute.For<IServiceCollection>();
var servicesCollection = Substitute.For<IServiceCollection>();
var metricPusher = Substitute.For<IMetricPusher>();

Action act = () => servicesCollection.AddMetricPusherService(null, TimeSpan.FromSeconds(1));
Action act = () => servicesCollection.AddMetricPusherService(metricPusher, TimeSpan.Zero);

act.Should().Throw<ArgumentNullException>();
}
act.Should().Throw<ArgumentOutOfRangeException>();
}

[Fact]
public void AddMetricPusherService_WithZeroTimeInterval_ThrowsArgumentOutOfRangeException()
{
var servicesCollection = Substitute.For<IServiceCollection>();
var metricPusher = Substitute.For<IMetricPusher>();
[Fact]
public void AddMetricPusherService_WithDefaultInterval_AddsMetricPusherServiceInServiceCollection()
{
var servicesCollection = new ServiceCollection();
var metricPusher = Substitute.For<IMetricPusher>();

Action act = () => servicesCollection.AddMetricPusherService(metricPusher, TimeSpan.Zero);
servicesCollection.AddMetricPusherService(metricPusher);
var provider = servicesCollection.BuildServiceProvider();
var service = provider.GetRequiredService<IHostedService>();

act.Should().Throw<ArgumentOutOfRangeException>();
}
service.Should().BeOfType<MetricPusherService>();
}

[Fact]
public void AddMetricPusherService_WithValidParameterValues_AddsMetricPusherServiceInServiceCollection()
{
var servicesCollection = new ServiceCollection();
var metricPusher = Substitute.For<IMetricPusher>();
[Fact]
public void AddMetricPusherService_WithValidParameterValues_AddsMetricPusherServiceInServiceCollection()
{
var servicesCollection = new ServiceCollection();
var metricPusher = Substitute.For<IMetricPusher>();

servicesCollection.AddMetricPusherService(metricPusher, TimeSpan.FromSeconds(1));
var provider = servicesCollection.BuildServiceProvider();
var service = provider.GetRequiredService<IHostedService>();
servicesCollection.AddMetricPusherService(metricPusher, TimeSpan.FromSeconds(1));
var provider = servicesCollection.BuildServiceProvider();
var service = provider.GetRequiredService<IHostedService>();

service.Should().BeOfType<MetricPusherService>();
}
service.Should().BeOfType<MetricPusherService>();
}
}

0 comments on commit 1db780d

Please sign in to comment.