Click or drag to resize

How To implement a timer job

Implementing your own Packflow jobs can be useful to run background or long running tasks on your server.

Basic implementation

These are the required steps to implement a Packflow job.

  1. Add a new class to your application inheriting PFJob

  2. In the newly created class, override the Execute method. Your job logic goes here.

  3. Override the Description property to provide a user friendly description of your job.

  4. Use OnProgressionChanged() to provide feedback about your job execution.

Example
C#
public class MyTimerJob : PFJob
{
    public MyTimerJob(PFSite site)
    : base(site)
    {
        /*Do not add code here */
    }

    public override string Description
    {
        get { return "A friendly description of your job's goal"; }
    }

    protected override void Execute()
    {
        //Packflow site is available:
        Site.Applications.GetAll();

        //Standard PACKFlow logger is available
        Logger.Information("Timer Job executing");

        //Use OnProgressionChanged to provide user with feedback;
        OnProgressionChanged(99, "Timer Job succesfully executed");

    }
}
Job Parameters

You may implement user-definable, persistent parameters.

Use PFJobParameter attribute to turn properties into persistant parameters for your Timer Job. Packflow handles structure types or Packflow objects inheriting PFBaseObject Use (use JobParameterType) to set parameter type.

C#
[PFJobParameter("Packflow Application", JobParameterType.Packflow, true, DisplayMember = "Name")]
public PFApplication Application { get; set; }

[PFJobParameter("Page Size", JobParameterType.SimpleType, true)]
public int PageSize { get; set; }

Use PFJobParameterChoice attribute to provide the user a dynamic list of choices for a parameter.

C#
[PFJobParameterChoice("Packflow Application")]
public List<PFApplication> PackflowApplicationsChoices
{
    get { return Site.Applications.GetAll(); }
}


[PFJobParameterChoice("Page Size")]
public List<int> PageSizeChoices
{
    get { return new List<int>() { 20, 50, 100 }; }
}

InitJob method is useful to set default parameters values in compliance with persistance mechanism.

C#
protected override void InitJob()
{
    base.InitJob();
    PageSize = 50;
}

Override Validate to throw an exception if your validation conditions fail. Validation should be related to job parameters only.

C#
public override void Validate()
{
    if (Application == null)
    {
        PFJobValidationException exp = new PFJobValidationException();
        exp.AddValidationError("Application", "Application cannot be null");
        throw exp;
    }
}
Security

It is possible to restrict users allowed execute the Job. Simply override the GetRunUsers method on your Job class to return a list of allowed users.

The base method returns the system accounts 'SystemAdmin' and 'SystemInstaller'.

C#
protected override PFPrincipalSet GetRunUsers()
{
    PFPrincipalSet result = PFPrincipalSet.Create(Site);
    PFGroup siteAdmins = Site.Groups.GetByName(PFStandardGroup.StandardGroupName_SiteAdmins);
    PFUserCollection authorizedUsers = siteAdmins.GetUsersRecursive();
    result.Users = authorizedUsers;

    return result;
}
Security note Security Note

When calling Run() or RunAsync() on a PFJob, the code executes under the current site user's identity. If calling from custom code, this will correspond to logged user's identity.

On the other hand, when a PFJob is scheduled via administration, it will run within the scheduler's process, which most probably runs under SystemAdmin identity.

You should take execution context and RLS implications into account when implementing a PFJob.

See Also