I have a long-running process: IHostedService. It runs all day long calling different external apis (services) to pull in data. I would like to get notified if during this process any of these external services failed/exceptions got thrown, the process is taking longer than 30 min etc. How would I set it up?
After some research, I ended up with this: https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/health-checks?view=aspnetcore-5.0#separate-readiness-and-liveness-probes (StartupHostedServiceHealthCheck section)
How do I implement .NET Core Health Checks on a Hosted Service?
This is what I have so far:
// Registered as Singleton
public interface IHostedServiceStatus
{
bool IsHostedServiceRunning { get; set; }
DateTime RunTime { get; }
string Message { get; }
void Setup(string name, DateTime runTime, string message = null);
}
public class HostedServiceStatus : IHostedServiceStatus
{
private string _message;
private string _name;
public string Message => $"HostedService {_name} started on: {RunTime} failed to complete. {_message}";
public bool IsHostedServiceRunning { get; set; }
public DateTime RunTime { get; private set; }
public void Setup(string name, DateTime runTime, string message = null)
{
_name = name;
RunTime = runTime;
IsHostedServiceRunning = true;
if (!string.IsNullOrEmpty(message))
_message = message;
}
}
// HealthCheck
public class HostedServiceHealthCheck : IHealthCheck
{
private readonly IHostedServiceStatus _hostedServiceStatus;
private readonly TimeSpan _duration = TimeSpan.FromMinutes(30);
public HostedServiceHealthCheck(IHostedServiceStatus hostedServiceStatus)
{
_hostedServiceStatus = hostedServiceStatus;
}
public Task<HealthCheckResult> CheckHealthAsync(
HealthCheckContext context,
CancellationToken cancellationToken = default)
{
if (_hostedServiceStatus.IsHostedServiceRunning)
{
if (_hostedServiceStatus.RunTime.Subtract(DateTime.Now).Duration() >= _duration)
return Task.FromResult(
HealthCheckResult.Unhealthy(_hostedServiceStatus.Message));
}
return Task.FromResult(
HealthCheckResult.Healthy("Task is finished."));
}
}
// Long running process
public async void Process(object state)
{
// each service runs about 10 min
foreach (var externalService in externalServices)
{
try
{
_hostedServiceStatus.Setup(externalService.Name, DateTime.Now); // setup healthcheckStatus - injected
...
// calls externalService gets data and saves to db
_dataMinerStatus.IsHostedServiceRunning = false; // udpate Healthcheck - finished successfully
}
catch (Exception ex)
{
// set MInDateTime so that it becamse UnHealthy
_hostedServiceStatus.Setup(externalService.Name, DateTime.MinValue);
// HealthCheck injected
await _healthCheck.CheckHealthAsync(new HealthCheckContext()); // send notification? (webhook setup) - will this work?
}
}