when applying any operation except recurrent, we cannot specify the queue name.
Example:
BackgroundJob.Schedule(
() => Console.WriteLine("Hello, world"),
TimeSpan.FromDays(1));
Something like this would be great:
BackgroundJob.Schedule(
() => Console.WriteLine("Hello, world"),
TimeSpan.FromDays(1),
"application-1");
closest and related existing tickets -
https://github.com/HangfireIO/Hangfire/issues/228
https://github.com/HangfireIO/Hangfire/issues/406
this work-around looks to work (I have done the scheduled for now.)
Client
1) provide more data in the ScheduledState, put in a location (ie classlib/dll) which the client can access (does not matter much about the background server)
public class ScheduledState : IState
{
public static readonly string StateName = "Scheduled";
public ScheduledState(TimeSpan enqueueIn, string queue = "default")
: this(DateTime.UtcNow.Add(enqueueIn), queue)
{
}
[JsonConstructor]
public ScheduledState(DateTime enqueueAt, string queue = "default")
{
EnqueueAt = enqueueAt;
ScheduledAt = DateTime.UtcNow;
Queue = queue;
}
public DateTime EnqueueAt { get; }
public DateTime ScheduledAt { get; }
public string Queue { get; }
public string Name => StateName;
public string Reason { get; set; }
public bool IsFinal => false;
public bool IgnoreJobLoadException => false;
public Dictionary<string, string> SerializeData()
{
return new Dictionary<string, string>
{
{ "Queue", Queue },
{ "EnqueueAt", JobHelper.SerializeDateTime(EnqueueAt) },
{ "ScheduledAt", JobHelper.SerializeDateTime(ScheduledAt) }
};
}
}
Server
2) add a filter (i chose to use an elect one)
public class UseQueueFromScheduledFilter : IJobFilter, IElectStateFilter
{
public void OnStateElection(ElectStateContext context)
{
var enqueuedState = context.CandidateState as EnqueuedState;
if (enqueuedState != null )
{
var stateData = context.Connection.GetStateData(context.BackgroundJob.Id);
string queueName;
if (stateData.Data.TryGetValue("Queue", out queueName))
{
enqueuedState.Queue = queueName;
}
}
}
server
3) register this (UseQueueFromScheduledFilter ) and also the PreserveOriginalQueueAttribute filter (located here https://github.com/HangfireIO/Hangfire/pull/502#issuecomment-176744750)
these filters will ensure that the job queued in the correct place for the first use and any retry.
Client
4) Schedule a task.
```
ScheduledState scheduledState = new Core.ScheduledState(new TimeSpan(0, 0, 1, 0), "my_app");
var b = new BackgroundJobClient();
b.Create(
() => Console.WriteLine("Hello, world3!"),
scheduledState);
```
the code above uses the state from step 1. not the state located in hangfire.
forgot to mention
client
1a) unregister the existing and register the following
public class StateHandler : IStateHandler
{
public void Apply(ApplyStateContext context, IWriteOnlyTransaction transaction)
{
var scheduledState = context.NewState as ScheduledState;
var originalScheduledState = context.NewState as Hangfire.States.ScheduledState;
if (scheduledState == null && originalScheduledState == null)
{
throw new InvalidOperationException(
$"`{GetType().FullName}` state handler can be registered only for the Scheduled state.");
}
var datetime = scheduledState?.EnqueueAt ?? originalScheduledState.EnqueueAt;
var timestamp = JobHelper.ToTimestamp(datetime);
transaction.AddToSet("schedule", context.BackgroundJob.Id, timestamp);
}
public void Unapply(ApplyStateContext context, IWriteOnlyTransaction transaction)
{
transaction.RemoveFromSet("schedule", context.BackgroundJob.Id);
}
// ReSharper disable once MemberHidesStaticFromOuterClass
public string StateName => ScheduledState.StateName;
}
@dbones hi,i used your code ,but when i run it ,threw a exception is
"InvalidOperationException: Hangfire.States.ScheduledState+Handler state handler can be registered only for the Scheduled state."
so i want to ask you what is the mean you said "forgot to mention"?
Most helpful comment
this work-around looks to work (I have done the scheduled for now.)
Client
1) provide more data in the ScheduledState, put in a location (ie classlib/dll) which the client can access (does not matter much about the background server)
Server
2) add a filter (i chose to use an elect one)
server
3) register this (UseQueueFromScheduledFilter ) and also the PreserveOriginalQueueAttribute filter (located here https://github.com/HangfireIO/Hangfire/pull/502#issuecomment-176744750)
these filters will ensure that the job queued in the correct place for the first use and any retry.
Client
4) Schedule a task.
```
ScheduledState scheduledState = new Core.ScheduledState(new TimeSpan(0, 0, 1, 0), "my_app");
```
the code above uses the state from step 1. not the state located in hangfire.