You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何判断.NET Core WebAPI是否空闲?有没有状态监控NuGet包?

判断.NET Core Minimal API的空闲状态及监控方案

一、自定义实现空闲状态判断

最直接的方式是通过中间件+全局状态追踪实现,核心思路是监控请求的开始与结束,统计活跃请求数并记录最后请求时间:

1. 实现请求追踪中间件

创建中间件维护请求计数和最后请求时间:

public class RequestTrackingMiddleware
{
    private readonly RequestDelegate _next;
    private static int _activeRequests;
    private static DateTime _lastRequestTime;

    public RequestTrackingMiddleware(RequestDelegate next)
    {
        _next = next;
        _lastRequestTime = DateTime.UtcNow;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        Interlocked.Increment(ref _activeRequests);
        try
        {
            _lastRequestTime = DateTime.UtcNow;
            await _next(context);
        }
        finally
        {
            Interlocked.Decrement(ref _activeRequests);
        }
    }

    // 暴露静态方法供外部判断空闲状态
    public static bool IsIdle(TimeSpan idleThreshold)
    {
        return _activeRequests == 0 && 
               DateTime.UtcNow - _lastRequestTime >= idleThreshold;
    }
}

// 扩展方法注册中间件
public static class RequestTrackingMiddlewareExtensions
{
    public static IApplicationBuilder UseRequestTracking(this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<RequestTrackingMiddleware>();
    }
}

2. 在Minimal API中注册中间件

在Program.cs中添加中间件(需放在路由映射之前):

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

// 注册请求追踪中间件
app.UseRequestTracking();

// 你的API路由
app.MapGet("/", () => "Hello World!");
app.MapPost("/data", (MyData data) => Results.Ok(data));

app.Run();

3. 检查空闲状态

可在Hosted Service或其他服务中定时调用RequestTrackingMiddleware.IsIdle(TimeSpan.FromSeconds(30))判断应用是否空闲。

二、状态监控与订阅钩子的实现

没有专门针对“空闲状态订阅”的官方NuGet包,但可通过以下方式实现:

1. 自定义可订阅的状态监控服务

基于IObservable实现服务,允许其他组件订阅空闲状态变更:

public class IdleMonitorService : IObservable<bool>, IDisposable
{
    private readonly List<IObserver<bool>> _observers = new();
    private readonly IHostApplicationLifetime _appLifetime;
    private Timer? _checkTimer;
    private bool _isIdle;
    private readonly TimeSpan _idleThreshold;

    public IdleMonitorService(IHostApplicationLifetime appLifetime, IOptions<IdleMonitorSettings> settings)
    {
        _appLifetime = appLifetime;
        _idleThreshold = settings.Value.IdleThreshold;
        
        // 应用启动后开始定时检查
        _appLifetime.ApplicationStarted.Register(StartMonitoring);
        _appLifetime.ApplicationStopping.Register(StopMonitoring);
    }

    private void StartMonitoring()
    {
        _checkTimer = new Timer(CheckIdleState, null, TimeSpan.Zero, TimeSpan.FromSeconds(5));
    }

    private void StopMonitoring()
    {
        _checkTimer?.Dispose();
    }

    private void CheckIdleState(object? state)
    {
        var newIdleState = RequestTrackingMiddleware.IsIdle(_idleThreshold);
        if (newIdleState != _isIdle)
        {
            _isIdle = newIdleState;
            foreach (var observer in _observers)
            {
                observer.OnNext(_isIdle);
            }
        }
    }

    public IDisposable Subscribe(IObserver<bool> observer)
    {
        if (!_observers.Contains(observer))
            _observers.Add(observer);
        return new Unsubscriber(_observers, observer);
    }

    public void Dispose()
    {
        StopMonitoring();
        foreach (var observer in _observers)
        {
            observer.OnCompleted();
        }
        _observers.Clear();
    }

    private class Unsubscriber : IDisposable
    {
        private readonly List<IObserver<bool>> _observers;
        private readonly IObserver<bool> _observer;

        public Unsubscriber(List<IObserver<bool>> observers, IObserver<bool> observer)
        {
            _observers = observers;
            _observer = observer;
        }

        public void Dispose()
        {
            if (_observers.Contains(_observer))
                _observers.Remove(_observer);
        }
    }
}

// 配置类
public class IdleMonitorSettings
{
    public TimeSpan IdleThreshold { get; set; } = TimeSpan.FromSeconds(30);
}

// 注册服务
public static class IdleMonitorServiceExtensions
{
    public static IServiceCollection AddIdleMonitor(this IServiceCollection services, Action<IdleMonitorSettings> configure)
    {
        services.Configure(configure);
        services.AddSingleton<IdleMonitorService>();
        return services;
    }
}

2. 使用现有监控库扩展

  • Microsoft.Extensions.Diagnostics.HealthChecks:可自定义健康检查,将空闲状态纳入健康状态判断,需自行实现状态变更的订阅逻辑。
  • App.Metrics:可收集请求吞吐量、活跃请求数等指标,基于指标判断空闲状态,并通过其事件系统订阅指标变化触发状态通知。

使用示例

在Hosted Service中订阅空闲状态变更:

public class IdleNotificationService : BackgroundService
{
    private readonly IdleMonitorService _idleMonitor;
    private IDisposable? _subscription;

    public IdleNotificationService(IdleMonitorService idleMonitor)
    {
        _idleMonitor = idleMonitor;
    }

    protected override Task ExecuteAsync(CancellationToken stoppingToken)
    {
        _subscription = _idleMonitor.Subscribe(new IdleObserver());
        return Task.CompletedTask;
    }

    public override void Dispose()
    {
        _subscription?.Dispose();
        base.Dispose();
    }

    private class IdleObserver : IObserver<bool>
    {
        public void OnNext(bool isIdle)
        {
            Console.WriteLine(isIdle ? "应用进入空闲状态" : "应用退出空闲状态");
        }

        public void OnError(Exception error)
        {
            // 处理错误
        }

        public void OnCompleted()
        {
            // 处理完成
        }
    }
}

内容的提问来源于stack exchange,提问作者davincikuo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 04:15:43