pieceofsummer / Hangfire.Console

Job console extension for Hangfire
MIT License
435 stars 80 forks source link

StartedAt Exception when triggering recurring job #66

Open vimception opened 6 years ago

vimception commented 6 years ago

I get the following exception when I trigger a recurring job from the hangfire UI:

System.Collections.Generic.KeyNotFoundException The given key 'StartedAt' was not present in the dictionary.

System.Collections.Generic.KeyNotFoundException: The given key 'StartedAt' was not present in the dictionary.
   at System.Collections.Generic.Dictionary`2.get_Item(TKey key)
   at Hangfire.Console.Server.ConsoleServerFilter.OnPerforming(PerformingContext filterContext)
   at Hangfire.Server.BackgroundJobPerformer.InvokePerformFilter(IServerFilter filter, PerformingContext preContext, Func`1 continuation)

Exception is persistent, even after cleaning entire project and dropping the hangfire database. Using latest version, 1.40.

If any further details can help, please let me know.

Thanks a lot.

pieceofsummer commented 6 years ago

Oh, this feels pretty weird, because Processing state must have StartedAt field.

I can only think of two possible reasons for this to happen:

  1. Job storage you’re using is broken, and doesn’t properly serialize state properties.
  2. You have altered Hangfire’s json serializer settings, so it now serializes them differenty (e.g. with camel case or whatever).
vimception commented 6 years ago

You sir, are spot on! The second reason is what's going on.

I changed the default Newtonsoft.Json serialization settings in my application. Not knowing, and expecting!, that this would influence Hangfire behaviour.

JsonConvert.DefaultSettings = () =>
{
    return new JsonSerializerSettings()
    {
        ContractResolver = new CamelCasePropertyNamesContractResolver(),
        ...
     };
};

However, I would expect a library to shield itself from this. For example, looking at https://github.com/pieceofsummer/Hangfire.Console/blob/master/src/Hangfire.Console/Dashboard/JobProgressDispatcher.cs#L65 the following is used:

var serialized = JsonConvert.SerializeObject(result);

But probably the own serialization settings should be explicitly set each time:

var settings = new JsonSerializerSettings();
settings.ContractResolver = new ...

var serialized = JsonConvert.SerializeObject(result, settings);

So this might be the root cause?

pieceofsummer commented 6 years ago

Indeed, I’d been negligent about that line. Thanks for mentioning it, will fix it in the future updates.

However, it is a minor issue. The worst could happen is progress indicator not shown (because of job ids serialized with a wrong case), and only for storages where job ids are alphanumeric.

The major issue is serializing of state data inside Hangfire itself. Both internal state renderers and extensions are expecting for state properties to have original letter casing.

And if they don’t, well, things would either silently fail (e.g. job history missing all the details, like job duration, latency, return value etc.), or they would fail with exception above.

/cc @odinserj