Creating a Custom Scheduled Task in Moodle to Clean Up Old Log Entries
Learn how to create a Moodle scheduled task that runs periodic PHP code, with a concrete example for cleaning up old log entries, testing via CLI, and verification steps.
08 Nov 2025, 16:40 UTC

Problem: Keeping Moodle logs from growing without manual intervention
Over time, Moodle’s log tables can accumulate millions of rows, slowing queries and consuming disk space. Administrators often need a reliable way to purge old entries on a regular schedule without relying on ad‑hoc scripts or manual database jobs.
Thesis: A custom scheduled task lets you run periodic PHP code inside Moodle’s cron framework, giving you full access to the Moodle API while keeping execution isolated from web requests.
1. Define the task class
Create a PHP class that extends \core\task\scheduled_task and implements the execute() method. The class lives in your plugin’s classes/task/ folder.
<?php
namespace local_logcleanup\task;
use core\task\scheduled_task;
class cleanup_old_logs extends scheduled_task {
/** @return string Human‑readable name shown in the UI */
public function get_name() {
return get_string('pluginname', 'local_logcleanup');
}
/** @return string Description shown in the UI */
public function get_description() {
return get_string('task_cleanup_desc', 'local_logcleanup');
}
/** @return void Core work – delete logs older than 90 days */
public function execute() {
global $DB;
$cutoff = time() - (90 * DAYSECS);
$DB->delete_records_select('logstore_standard_log', 'timecreated < ?', [$cutoff]);
// Optional: write a custom log entry for auditing
$this->set_custom_data('Deleted logs older than ' . gmdate('Y-m-d', $cutoff));
}
}
?>
2. Register the task in db/tasks.php
Add an entry that tells Moodle the class name, a friendly name, and the default cron schedule. The example below schedules the task to run daily at 02:30 AM.
<?php
$tasks = [
[
'classname' => '\\local_logcleanup\\task\\cleanup_old_logs',
'blocked' => 0,
'minute' => 30,
'hour' => 2,
'day' => '*',
'month' => '*',
'dayofweek' => '*',
],
];
?>
3. Test the task instantly from the command line
Before waiting for cron, you can invoke the task directly. This runs the execute() method in the same PHP environment as cron but without waiting for the schedule.
php admin/tool/task/cli/schedule_task.php --execute=\\\\local_logcleanup\\task\\cleanup_old_logs
Run this from the Moodle root directory with the web‑server user (e.g., www-data) to ensure file permissions match those used by cron.
4. Verify the task is working
- Scheduled tasks report: Go to Site administration → Reports → Scheduled tasks. Your new task should appear with the next run time matching the cron expression you set.
- CLI test output: After running the command above, check any expected side‑effects (e.g., fewer rows in
mdl_logstore_standard_log) or look for a custom log entry viaget_string('task_cleanup_desc', 'local_logcleanup')in the admin logs. - Cron log: Visit Site administration → Reports → Cron logs and confirm that an entry for your task appears at the scheduled interval without error messages.
Trade‑off and limitation
Scheduled tasks share the same PHP process as Moodle’s cron. If the execute() method performs heavy database writes or long external HTTP calls, it can block cron and delay other tasks. A common mitigation is to split work into chunks: process a limited number of rows per execution and store progress in a custom table or state variable, then reschedule the task via core\task\manager::queue_adhoc_task() until the work is complete.
Actionable closing
After adding the task class and updating db/tasks.php, bump your plugin’s version number and run php admin/cli/upgrade.php so Moodle registers the new task. From there, monitor the scheduled tasks report and cron logs to ensure the cleanup runs as expected. With this pattern you can safely automate any periodic maintenance—cleanup, report generation, data synchronization—while staying inside Moodle’s supported cron infrastructure.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.