diff --git a/src/Hangfire.Core/Storage/IMonitoringApi.cs b/src/Hangfire.Core/Storage/IMonitoringApi.cs index 31a8939f6..80402b10f 100644 --- a/src/Hangfire.Core/Storage/IMonitoringApi.cs +++ b/src/Hangfire.Core/Storage/IMonitoringApi.cs @@ -31,6 +31,7 @@ public interface IMonitoringApi JobList ProcessingJobs(int from, int count); JobList ScheduledJobs(int from, int count); + JobList ScheduledJobsByIds(long[] jobIds); JobList SucceededJobs(int from, int count); JobList FailedJobs(int from, int count); JobList DeletedJobs(int from, int count); diff --git a/src/Hangfire.Core/Storage/JobStorageMonitor.cs b/src/Hangfire.Core/Storage/JobStorageMonitor.cs index 08ba493e9..fa970e18c 100644 --- a/src/Hangfire.Core/Storage/JobStorageMonitor.cs +++ b/src/Hangfire.Core/Storage/JobStorageMonitor.cs @@ -30,6 +30,7 @@ public abstract class JobStorageMonitor : IMonitoringApi public abstract JobList FetchedJobs(string queue, int from, int perPage); public abstract JobList ProcessingJobs(int from, int count); public abstract JobList ScheduledJobs(int from, int count); + public abstract JobList ScheduledJobsByIds(long[] jobIds); public abstract JobList SucceededJobs(int from, int count); public abstract JobList FailedJobs(int from, int count); public abstract JobList DeletedJobs(int from, int count); diff --git a/src/Hangfire.SqlServer/SqlServerMonitoringApi.cs b/src/Hangfire.SqlServer/SqlServerMonitoringApi.cs index f8f7dc877..018af0876 100644 --- a/src/Hangfire.SqlServer/SqlServerMonitoringApi.cs +++ b/src/Hangfire.SqlServer/SqlServerMonitoringApi.cs @@ -114,6 +114,27 @@ public override JobList ScheduledJobs(int @from, int count) })); } + public override JobList ScheduledJobsByIds(long[] jobIds) + { + if (jobIds.Length == 0) + throw new InvalidOperationException("Sequence contains no elements"); + + return UseConnection(connection => GetJobsByIdsList( + connection, + jobIds, + ScheduledState.StateName, + (sqlJob, job, invocationData, loadException, stateData) => new ScheduledJobDto + { + Job = job, + LoadException = loadException, + InvocationData = invocationData, + InScheduledState = ScheduledState.StateName.Equals(sqlJob.StateName, StringComparison.OrdinalIgnoreCase), + EnqueueAt = JobHelper.DeserializeNullableDateTime(stateData["EnqueueAt"]) ?? DateTime.MinValue, + ScheduledAt = sqlJob.StateChanged, + StateData = stateData + })); + } + public override IDictionary SucceededByDatesCount() { return UseConnection(connection => @@ -626,6 +647,27 @@ private JobList GetJobs( return DeserializeJobs(jobs, selector); } + private JobList GetJobsByIdsList( + DbConnection connection, + long[] jobIds, + string stateName, + Func, TDto> selector) + { + string jobsSql = +$@";select j.*, s.Reason as StateReason, s.Data as StateData, s.CreatedAt as StateChanged +from [{_storage.SchemaName}].Job j with (nolock, forceseek) +left join [{_storage.SchemaName}].State s with (nolock, forceseek) on j.StateId = s.Id and j.Id = s.JobId +where j.Id in @ids"; + + var jobs = connection.Query( + jobsSql, + new { stateName = stateName , ids = jobIds }, + commandTimeout: _storage.CommandTimeout) + .ToList(); + + return DeserializeJobs(jobs, selector); + } + private static JobList DeserializeJobs( ICollection jobs, Func, TDto> selector)