admin管理员组文章数量:1356003
I have a background service in C# that I want to check the health of the background service.
Whether it is running or in error or stopped, then I want to see the status of the background service health via a Web API GET
method. In the background service process, when the service starts status is set to running, if stops it is set to stopped (and so on).
I tried using
webBuilder.UseKestrel(options => options.ListenAnyIP(5000)});
via CreateWebHostBuilder
, use singleton to register the worker process.
In the other Web API project, I have a project reference to this worker process and register it in the program.cs
as a singleton.
public class Worker: BackgroundService {}
The issue is the controller get method I have doesn't show the right value, I inject the worker process and access the status variable, it always shows the same value.
In the controller method:
public IActionResult Get()
{
return Ok(_worker.Status);
}
How can I get real time health status from a background service through a http call that happens outside of the worker process project?
Is there a better option/approach for this?
Code - Worker.cs
:
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System;
using System.Threading;
using System.Threading.Tasks;
namespace MyBackgroundServiceHealth
{
public class Worker : BackgroundService
{
private readonly ILogger<Worker> _logger;
private IHost _webHost = null!;
private string _status = "Healthy";
public string Status => _status;
public Worker(ILogger<Worker> logger)
{
_logger = logger;
}
public override async Task StartAsync(CancellationToken cancellationToken)
{
try
{
_logger.LogInformation("Starting the service...");
_webHost = CreateWebHostBuilder().Build();
await _webHost.StartAsync(cancellationToken);
_status = "Running";
_logger.LogInformation("Service started. Status: {status}", _status);
await base.StartAsync(cancellationToken);
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to start the service.");
_status = "Not Running";
_logger.LogInformation("Service failed to start. Status: {status}", _status);
}
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
try
{
while (!stoppingToken.IsCancellationRequested)
{
if (_logger.IsEnabled(LogLevel.Information))
{
_logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
}
await Task.Delay(180000, stoppingToken);
}
}
catch (Exception ex)
{
_logger.LogError(ex, "An error occurred during execution.");
_status = "Error";
_logger.LogInformation("Service encountered an error. Status: {status}", _status);
}
}
public override async Task StopAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Stopping the service...");
_status = "Stopping";
_logger.LogInformation("Service is stopping. Status: {status}", _status);
await _webHost.StopAsync(cancellationToken);
await base.StopAsync(cancellationToken);
_status = "Stopped";
_logger.LogInformation("Service stopped. Status: {status}", _status);
}
private IHostBuilder CreateWebHostBuilder() =>
Host.CreateDefaultBuilder()
.ConfigureWebHost(webBuilder =>
{
webBuilder.ConfigureServices(services =>
{
services.AddSingleton<Worker>();
services.AddControllers();
});
webBuilder.Configure(app =>
{
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
});
webBuilder.UseKestrel(options =>
{
options.ListenAnyIP(5000);// Listen on port 5000
});
});
}
}
In program.cs
of the background service, I have this code:
using MyBackgroundServiceHealth;
var builder = Host.CreateApplicationBuilder(args);
// Register the Worker as a singleton service for dependency injection
builder.Services.AddSingleton<Worker>();
builder.Services.AddSingleton<IHostedService>(sp=>sp.GetRequiredService<Worker>());
var host = builder.Build();
host.Run();
Controller:
[Route("api/[controller]")]
[ApiController]
public class HealthController : ControllerBase
{
private readonly Worker _worker;
private readonly ILogger<HealthController> _logger;
public HealthController(Worker worker, ILogger<HealthController> logger)
{
_worker = worker;
_logger = logger;
}
[HttpGet]
public IActionResult Get()
{
_logger.LogInformation("Health check status: {status}", _worker.Status);
return Ok(_worker.Status);
}
}
In the Web API program.cs
:
builder.Services.AddSingleton<Worker>();
builder.Services.AddSingleton<IHostedService>(sp => sp.GetRequiredService<Worker>());
I have a background service in C# that I want to check the health of the background service.
Whether it is running or in error or stopped, then I want to see the status of the background service health via a Web API GET
method. In the background service process, when the service starts status is set to running, if stops it is set to stopped (and so on).
I tried using
webBuilder.UseKestrel(options => options.ListenAnyIP(5000)});
via CreateWebHostBuilder
, use singleton to register the worker process.
In the other Web API project, I have a project reference to this worker process and register it in the program.cs
as a singleton.
public class Worker: BackgroundService {}
The issue is the controller get method I have doesn't show the right value, I inject the worker process and access the status variable, it always shows the same value.
In the controller method:
public IActionResult Get()
{
return Ok(_worker.Status);
}
How can I get real time health status from a background service through a http call that happens outside of the worker process project?
Is there a better option/approach for this?
Code - Worker.cs
:
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System;
using System.Threading;
using System.Threading.Tasks;
namespace MyBackgroundServiceHealth
{
public class Worker : BackgroundService
{
private readonly ILogger<Worker> _logger;
private IHost _webHost = null!;
private string _status = "Healthy";
public string Status => _status;
public Worker(ILogger<Worker> logger)
{
_logger = logger;
}
public override async Task StartAsync(CancellationToken cancellationToken)
{
try
{
_logger.LogInformation("Starting the service...");
_webHost = CreateWebHostBuilder().Build();
await _webHost.StartAsync(cancellationToken);
_status = "Running";
_logger.LogInformation("Service started. Status: {status}", _status);
await base.StartAsync(cancellationToken);
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to start the service.");
_status = "Not Running";
_logger.LogInformation("Service failed to start. Status: {status}", _status);
}
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
try
{
while (!stoppingToken.IsCancellationRequested)
{
if (_logger.IsEnabled(LogLevel.Information))
{
_logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
}
await Task.Delay(180000, stoppingToken);
}
}
catch (Exception ex)
{
_logger.LogError(ex, "An error occurred during execution.");
_status = "Error";
_logger.LogInformation("Service encountered an error. Status: {status}", _status);
}
}
public override async Task StopAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Stopping the service...");
_status = "Stopping";
_logger.LogInformation("Service is stopping. Status: {status}", _status);
await _webHost.StopAsync(cancellationToken);
await base.StopAsync(cancellationToken);
_status = "Stopped";
_logger.LogInformation("Service stopped. Status: {status}", _status);
}
private IHostBuilder CreateWebHostBuilder() =>
Host.CreateDefaultBuilder()
.ConfigureWebHost(webBuilder =>
{
webBuilder.ConfigureServices(services =>
{
services.AddSingleton<Worker>();
services.AddControllers();
});
webBuilder.Configure(app =>
{
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
});
webBuilder.UseKestrel(options =>
{
options.ListenAnyIP(5000);// Listen on port 5000
});
});
}
}
In program.cs
of the background service, I have this code:
using MyBackgroundServiceHealth;
var builder = Host.CreateApplicationBuilder(args);
// Register the Worker as a singleton service for dependency injection
builder.Services.AddSingleton<Worker>();
builder.Services.AddSingleton<IHostedService>(sp=>sp.GetRequiredService<Worker>());
var host = builder.Build();
host.Run();
Controller:
[Route("api/[controller]")]
[ApiController]
public class HealthController : ControllerBase
{
private readonly Worker _worker;
private readonly ILogger<HealthController> _logger;
public HealthController(Worker worker, ILogger<HealthController> logger)
{
_worker = worker;
_logger = logger;
}
[HttpGet]
public IActionResult Get()
{
_logger.LogInformation("Health check status: {status}", _worker.Status);
return Ok(_worker.Status);
}
}
In the Web API program.cs
:
builder.Services.AddSingleton<Worker>();
builder.Services.AddSingleton<IHostedService>(sp => sp.GetRequiredService<Worker>());
Share
Improve this question
edited Mar 28 at 8:32
marc_s
756k184 gold badges1.4k silver badges1.5k bronze badges
asked Mar 28 at 5:34
Sharpeye500Sharpeye500
9,09326 gold badges97 silver badges148 bronze badges
6
- There is not enough code to do anything but wildly guess what may have gone wrong. Please add a minimal example demonstrating this problem. – nvoigt Commented Mar 28 at 7:12
- Wait, what are you trying to do here. Use a generic host & background service... to start another host inside it? Why add the extra layer of indirection? – Jeremy Lakeman Commented Mar 28 at 8:08
- That's Phase II; for Phase I, I send myself email messages when the "health monitor" detects an issue. I prefer to have the problem find me; instead of the other way around. – Gerry Schmitz Commented Mar 28 at 14:33
- I want to check the status of a worker backgroundservice say MySampleWorker which implements backgroundservice(running/stopped) via a http call(via API Controller), so, i can check the status outside independently. – Sharpeye500 Commented Mar 28 at 14:34
- I want to build a dashboard page that displays status of different worker processes, to me this is one approach, to make a rest call and then consume that in the ui. If you have other options, you can share that. – Sharpeye500 Commented Mar 28 at 15:34
1 Answer
Reset to default 2Let me guess, you registered the same service twice;
services.AddSingleton<Worker>();
services.AddHostedService<Worker>();
Which will result in two singleton instances, registered with different interfaces. You can ensure there's only one instance, by registering the other with a factory method;
services.AddSingleton<Worker>();
services.AddSingleton<IHostedService>(sp => sp.GetService<Worker>());
You could instead inject a IHostApplicationLifetime
dependency and .StopApplication();
if you catch any exceptions.
本文标签: cHealth check of a background service via REST callStack Overflow
版权声明:本文标题:c# - Health check of a background service via REST call - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744054680a2583053.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论