Let me share with how this is done in case of Hangfire, which is a popular job scheduler in .NET world. I use this as an example, because I have some experience with it and its source code is publicly available on github.
Enqueueing a recurring job
RecurringJob.AddOrUpdate(() => Console.WriteLine("Transparent!"), Cron.Daily);
The RecurringJob
class defines several overloads for AddOrUpdate
to accept different methodCall
parameters:
Expression<Action>
: Synchronous code without any parameter
Expression<Action<T>>
: Synchronous code with a single parameter
Expression<Func<Task>>
: Asynchronous code without any parameter
Expression<Func<T, Task>>
: Asynchronous code with a single parameter
The overloads are anticipating not just a delegate (a Func
or an Action
) rather an Expression
, because it allows to Hangfire to retrieve meta information about
- the type on which
- the given method should be called
Retrieving meta data
There is a class called Job
which exposes several FromExpression
overloads. All of them are calling this private method which does all the heavy lifting. It retrieves the type, method and argument meta data.
From the above example this FromExpression
retrieves the following data:
- type:
System.Console, mscorlib
- method:
WriteLine
- parameter type:
System.String
- argument:
"Transparent!"
These information will be stored inside the Job's properties: Type
, Method
and Args
.
Serializing meta info
The RecurringJobManager
receives this job and passes to a transaction
via a RecurringJobEntity
wrapper to perform an update if the definition of the job has changed or it was not registered at all.
Inside its GetChangedFields
method is where the serialization is done via a JobHelper
and a InvocationData
classes. Under the hood they are using Newtonsoft's json.net to perform the serialization.
Back to our example, the serialized job (without the cron expression) looks something like this
{
"t":"System.Console, mscorlib",
"m":"WriteLine",
"p":[
"System.String"
],
"a":[
"Transparent!"
]
}
This is what persisted inside the database and read from it whenever the job needs to be triggered.