Whether this driver is a BY-DESIGN high-frequency poller — a dispatcher that
sweeps a work queue on a tight cron (e.g. every minute) and does bounded work
per sweep. Overriding to true exempts jobs of this type from the engine's
high-frequency cron warning banner. Leave false for ordinary jobs: the
warning exists because a tight cron on a work job is usually a design smell.
ProtectedbuildThe WHERE clause selecting expired rows, or null when nothing can expire.
Returning null rather than a clause that matches nothing is deliberate — it lets the caller skip the query entirely on an instance where no action has ever configured retention, which is the common case and should cost nothing nightly.
ProtecteddeleteDeletes the given rows, counting rather than aborting on a failure.
One bad row — a FK an extension added, a permission gap — must not strand the rest of the purge behind it every night. The count is reported so the failure is visible.
ProtecteddistinctThe retention lifetimes actually in use, read from the actions that stamped them.
Read from MJ: Actions rather than by scanning the log for distinct values, because the log
is the large table and the actions table is not — and the two agree by construction, since the
stamp comes from here.
Execute the scheduled job
This is the main entry point for job execution. The plugin should:
The Details object will be serialized to JSON and stored in ScheduledJobRun.Details
Execution context including schedule, run record, and user
Promise resolving to execution result
ProtectedfindThe expired rows, oldest first, capped at maxDeletes.
Oldest-first is not cosmetic: a capped run that took an arbitrary slice would leave the same ancient rows behind every night while deleting newer ones, so the backlog would never drain.
Format notification content for job completion
Called by the engine when notifications are enabled and should be sent. The plugin can customize the notification based on the job type and execution result.
Execution context
The execution result
Notification content
ProtectedgetProtectedGet the job type entity for this plugin
The schedule
User context
Optionalprovider: IMetadataProviderPromise resolving to the job type entity
ProtectedlogProtectedLog execution progress
Log message
Whether to only log in verbose mode
ProtectedlogProtectedLog execution error
Error message
Optionalerror: anyOptional error object
ProtectedparseProtectedParse and validate the Configuration JSON field
Helper method for plugins to parse their configuration with type safety. Throws if configuration is invalid.
The configuration type
The schedule containing the configuration
Parsed configuration
Validate job-specific configuration
Called when creating or updating a scheduled job to ensure the Configuration JSON is valid for this job type.
The schedule being validated
Validation result with any errors or warnings
Purges expired
MJ: Action Execution Logsrows, bounded per run.Retention is decided at write time, not here.
StartActionLogstamps each row'sRetentionPeriodfrom its action's, so this job reads only the row's own value — which is what makes an edit toAction.RetentionPerioda going-forward change rather than a retroactive deletion of history written under the previous policy. A row with NULL retention is kept forever unless the job is explicitly configured withDefaultRetentionDays.Deletion goes through
BaseEntity.Delete(), one row at a time. ADELETEstatement would be faster and is a sanctioned use of raw DML in principle — but only for an entity that has opted in viaAllowDirectSQLDelete, and this one has not. Honouring the platform's own gate matters more here than throughput, because the job is bounded anyway: the cap exists so a first run against a long-neglected table cannot become an unbounded transaction, and raising it is a configuration change rather than a code change.Opt-in like every other maintenance driver: shipping the job type activates nothing until someone creates a
MJ: Scheduled Jobof this type with a cron expression.