如何在C#中阻止Quartz.NET定时任务在计算机非活跃时运行?
可行解决方案
针对Windows服务中Quartz任务需要跳过系统非活跃状态执行的需求,可通过结合Windows原生API实现状态校验,在任务执行前判断系统是否活跃,非活跃则直接跳过任务逻辑:
1. 实现系统活跃状态检查逻辑
通过调用两个核心Windows API,分别判断工作站锁定状态和用户输入空闲时长,组合得出当前系统是否处于活跃状态:
1.1 声明所需Windows API
在项目中添加API声明(需引用System.Runtime.InteropServices):
using System.Runtime.InteropServices; public static class SystemActivityHelper { [StructLayout(LayoutKind.Sequential)] private struct LASTINPUTINFO { public uint cbSize; public uint dwTime; } [DllImport("user32.dll")] private static extern bool GetLastInputInfo(ref LASTINPUTINFO plii); [DllImport("wtsapi32.dll")] private static extern bool WTSQuerySessionInformation(IntPtr hServer, int sessionId, WTS_INFO_CLASS wtsInfoClass, out IntPtr ppBuffer, out uint pBytesReturned); [DllImport("wtsapi32.dll")] private static extern void WTSFreeMemory(IntPtr pMemory); private enum WTS_INFO_CLASS { WTSSessionState = 11 } private enum WTS_CONNECTSTATE_CLASS { WTSActive, WTSConnected, WTSConnectQuery, WTSShadow, WTSDisconnected, WTSIdle, WTSListen, WTSReset, WTSDown, WTSInit } }
1.2 编写状态检查方法
在SystemActivityHelper中添加判断逻辑:
public static bool IsSystemActive() { // 优先检查工作站是否锁定 if (IsWorkstationLocked()) return false; // 检查用户输入空闲时长(示例:超过5分钟则判定为非活跃) int idleThresholdMinutes = 5; uint idleTimeMs = GetIdleTimeMs(); return idleTimeMs < idleThresholdMinutes * 60 * 1000; } private static uint GetIdleTimeMs() { LASTINPUTINFO lastInputInfo = new LASTINPUTINFO(); lastInputInfo.cbSize = (uint)Marshal.SizeOf(lastInputInfo); GetLastInputInfo(ref lastInputInfo); return (uint)Environment.TickCount - lastInputInfo.dwTime; } private static bool IsWorkstationLocked() { IntPtr buffer = IntPtr.Zero; uint bytesReturned; int currentSessionId = System.Diagnostics.Process.GetCurrentProcess().SessionId; try { if (WTSQuerySessionInformation(IntPtr.Zero, currentSessionId, WTS_INFO_CLASS.WTSSessionState, out buffer, out bytesReturned)) { WTS_CONNECTSTATE_CLASS state = (WTS_CONNECTSTATE_CLASS)Marshal.ReadInt32(buffer); return state == WTS_CONNECTSTATE_CLASS.WTSDisconnected; } return false; } finally { if (buffer != IntPtr.Zero) WTSFreeMemory(buffer); } }
2. 修改Quartz Job执行逻辑
在你的GetNetworkDataJob的Execute方法中,先执行状态检查,非活跃则跳过核心任务:
public class GetNetworkDataJob : IJob { public async Task Execute(IJobExecutionContext context) { // 先校验系统活跃状态 if (!SystemActivityHelper.IsSystemActive()) { // 可添加日志记录:系统非活跃,跳过本次任务执行 return; } // 执行你的核心任务逻辑 await GetNetworkDataAsync(); } private Task GetNetworkDataAsync() { // 你的任务实现代码 return Task.CompletedTask; } }
注意事项
- 权限说明:若服务运行在LocalSystem账户下,默认具备查询会话信息的权限;若使用自定义账户,需赋予其查询系统会话信息的相关权限。
- 阈值调整:可根据业务需求修改
idleThresholdMinutes的值,自定义用户输入空闲的判定标准。
内容的提问来源于stack exchange,提问作者Ben
相关产品推荐
相关产品推荐

