< Summary

Information
Class: Elsa.Hosting.Management.HostedServices.InstanceHeartbeatService
Assembly: Elsa.Hosting.Management
File(s): /home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Hosting.Management/HostedServices/InstanceHeartbeatService.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 23
Coverable lines: 23
Total lines: 72
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 4
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%210%
StartAsync(...)100%210%
StopAsync(...)0%620%
Dispose()0%620%
WriteHeartbeat(...)100%210%
WriteHeartbeatAsync()100%210%

File(s)

/home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Hosting.Management/HostedServices/InstanceHeartbeatService.cs

#LineLine coverage
 1using Elsa.Common;
 2using Elsa.Hosting.Management.Contracts;
 3using Elsa.Hosting.Management.Options;
 4using Elsa.KeyValues.Contracts;
 5using Elsa.KeyValues.Entities;
 6using JetBrains.Annotations;
 7using Microsoft.Extensions.DependencyInjection;
 8using Microsoft.Extensions.Hosting;
 9using Microsoft.Extensions.Options;
 10
 11namespace Elsa.Hosting.Management.HostedServices;
 12
 13/// <summary>
 14/// Service to write heartbeat messages per running instance.
 15/// </summary>
 16[UsedImplicitly]
 17public class InstanceHeartbeatService : IHostedService, IDisposable
 18{
 19    private readonly IServiceProvider _serviceProvider;
 20    private readonly HeartbeatOptions _heartbeatOptions;
 21    private Timer? _timer;
 22
 23    internal const string HeartbeatKeyPrefix = "Heartbeat_";
 24
 25    /// <summary>
 26    /// Creates a new instance of the <see cref="InstanceHeartbeatService"/>
 27    /// </summary>
 028    public InstanceHeartbeatService(IServiceProvider serviceProvider, IOptions<HeartbeatOptions> heartbeatOptions)
 29    {
 030        _serviceProvider = serviceProvider;
 031        _heartbeatOptions = heartbeatOptions.Value;
 032    }
 33
 34    /// <inheritdoc />
 35    public Task StartAsync(CancellationToken cancellationToken)
 36    {
 037        _timer = new Timer(WriteHeartbeat, null, TimeSpan.Zero, _heartbeatOptions.Interval);
 038        return Task.CompletedTask;
 39    }
 40
 41    /// <inheritdoc />
 42    public Task StopAsync(CancellationToken cancellationToken)
 43    {
 044        _timer?.Change(Timeout.Infinite, Timeout.Infinite);
 045        return Task.CompletedTask;
 46    }
 47
 48    /// <inheritdoc />
 49    public void Dispose()
 50    {
 051        _timer?.Dispose();
 052    }
 53
 54    private void WriteHeartbeat(object? state)
 55    {
 056        _ = Task.Run(async () => await WriteHeartbeatAsync());
 057    }
 58
 59    private async Task WriteHeartbeatAsync()
 60    {
 061        using var scope = _serviceProvider.CreateScope();
 062        var instanceNameProvider = scope.ServiceProvider.GetRequiredService<IApplicationInstanceNameProvider>();
 063        var store = scope.ServiceProvider.GetRequiredService<IKeyValueStore>();
 064        var systemClock = scope.ServiceProvider.GetRequiredService<ISystemClock>();
 065        await store.SaveAsync(new SerializedKeyValuePair
 066            {
 067                Id = $"{HeartbeatKeyPrefix}{instanceNameProvider.GetName()}",
 068                SerializedValue = systemClock.UtcNow.ToString("o")
 069            },
 070            default);
 071    }
 72}