Scheduled Jobs Updates
Some great updates have been delivered to EPiServer Scheduled Jobs infrastructure within version 10.3. In this blog post we will review some of the important changes.
Scanning Process
Property IsStoppable
is now calculated during scanning process. Scheduled jobs scanner detects whether job is stoppable or not. If so - it’s written down to the database and used later when job is being triggered.
Also - now with v10.3 you don’t need to inherit from base class (EPiServer.Scheduler.ScheduledJobBase
). In this case all you need is to have static string Execute()
method:
1
2
3
4
5
6
7
8
9
[ScheduledPlugIn(DisplayName = "My Custom Job"
GUID = "...")]
public class MyCustomJob
{
public static string Execute()
{
...
}
}
Not really sure why you would like to escape ScheduledJobBase
class and just have simple class with execution method tho.
Use case that pops in my mind could be when you want to reduce dependency on EPiServer infrastructure and libraries and have just simple class that serves as shell for the actual service or component. In this case scheduled job would become tiny fraction of outer thin slice of the system - with almost no dependencies on underlying execution engine.
Job Factory - DI Friendly!
Finally! Another great addition is IScheduledJobFactory
interface and corresponding implementation. As you might guess from the name of the type - it’s factory for the scheduled jobs.
It’s possible to override this factory with our own stuff, but mostly all of necessary functionality is there.
Most importantly - factory is DI (Dependency Injection) aware now! So you can write (not only specific to “method invocation based” jobs - with static string Execute()
method):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
[ScheduledPlugIn(DisplayName = "My Custom Job"
GUID = "...")]
public class MyCustomJob
{
public MyCustomJob(IContentTypeRepository repo)
{
...
}
public static string Execute()
{
...
}
}
Now you will not need to use ServiceLocator anti-pattern anymore in scheduled jobs. It was not good design.
Execution Model Changes
Another great change in v10.3 is addition of IScheduledJobExecutor
interface and corresponding implementation. This guy makes sure that job is executed correctly, keeps track of running jobs and gives opportunity to cancel (aka Stop) the job.
It doesn’t matter anymore how you execute the job (scheduler or manually) - with the help of this new interface now both modes are the same. You specify trigger options when you are firing the job (User
- manual execution):
1
2
3
4
5
6
7
8
9
private IScheduledJobExecutor _executor;
...
_executor.StartAsync(jobInstance,
new JobExecutionOptions
{
Trigger = ScheduledJobTrigger.User
});
Among other things, you can also specify whether you want to execute job asynchronous (default) or wait for the results immediately:
1
2
3
4
5
6
7
8
9
10
private IScheduledJobExecutor _executor;
...
_executor.StartAsync(jobInstance,
new JobExecutionOptions
{
Trigger = ScheduledJobTrigger.User,
RunSynchronously = true
});
Rename Jobs Safely
– What is hardest thing in IT?
– Right, naming!
To name scheduled job with first shot is pretty challenging and almost impossible :)
Before EPiServer v10.3 renaming of the scheduled jobs resulted in orphan jobs - ghost ones that are hanging around as obsolete records in the database and make unwanted noise in jobs listing. You can of course delete them from scheduled jobs overview plugin safely, but still - not so nice!
Now with support of [ScheduledPlugIn(GUID=...)]
attribute it’s possible to rename jobs safely without worrying to make stale data in the database.
1
2
3
4
5
6
[ScheduledPlugIn(DisplayName = "My Custom Job"
GUID = "ac034ea9-91d0-471b-821d-456b9072b465")]
public class MyCustomJob
{
...
}
We all are good copy/pasters. But, you will get an exception if you will forget to change GUID
of the copied job.
Measure Execution Cycle
Precise measure of job run cycle in some cases could be pretty important performance indicator. Now with latest version update it’s possible to get statistics about how long each run cycle took. It’s available in log viewer.
Increased Log Size
If job runs frequently - last 100 log entries might be not sufficient. Now this limitation is gone and you can jump back to history far enough.
Some Final Thoughts
Awesome to see improvements in stable infrastructure components as well. However - here are some thoughts from my side.
Still waiting for something similar as ScheduledJobs Overview plugin already built-in into EPiServer platform. This is one of the issue among others.
Would be helpful to see last job’s run cycle duration somewhere in job’s details page. Fortunately, this is visible in jobs overview page:
- Not sure why scanning process is kicked off from the attribute (
EPiServer.PlugIn.ScheduledPlugInAttribute
) and not some scanner implementation. As scheduled job is just yet another plugin for EPiServer - might be that this is coming from Plug-In system.
1
2
3
4
5
6
7
8
9
public class ScheduledPlugInAttribute : PlugInAttribute
{
internal static void Initialize()
{
ServiceLocator.Current
.GetInstance<IScheduledJobScanner>()
.Scan();
}
}
Even more, I couldn’t find any references to Start()
and AsyncStart()
methods within EPiServer code. Most probably they are invoked dynamically via method invocation. Which is even worse. But that’s a topic for another blog post..
Back to the [ScheduledPlugIn]
. As we know - attributes are just metadata. It should not have any behavior.
- I’m missing some nice overview of duration of last X cycles. That would help me to look for patterns and/or peeks in job execution cycles. Fortunately, overview plugin has one :)
Happy scheduling!
[eof]
Comments powered by Disqus.