LazyCron

Run scheduled jobs at fixed intervals without setting up a system cron job

LazyCron is triggered by normal page views (or by a real cron job/CLI call), checks whether any registered interval has elapsed, and fires the matching hook.

Because execution is piggy-backed on regular page views, intervals are guaranteed to be at least as long as specified — never shorter. Accuracy depends on site traffic. For precise timing, trigger LazyCron from a real cron job or the CLI.

$lazyCron = $modules->get('LazyCron');

Expand all      API reference

How it works

When LazyCron is installed and autoloaded, it hooks ProcessPageView::finished and runs pending jobs after the page response has been sent. This keeps cron overhead from slowing down the visitor experience.

If the module's CLI mode only setting is enabled (cliOnly), LazyCron does not run during HTTP requests. You then trigger it manually with php index.php lazycron run or with a system cron job such as:

wget --quiet --no-cache -O - https://www.example.com/ > /dev/null
Usage

In a module

Attach a hook to one of the interval methods in your module's init() or ready() method:

public function init() {
    $this->addHook('LazyCron::everyDay', $this, 'cleanupOldLogs');
}

public function cleanupOldLogs(HookEvent $event) {
    $secondsElapsed = $event->arguments(0);
    // run daily cleanup
}

In templates or site hooks

Use $wire->addHook() (or wire()->addHook()) with a globally defined callback function:

$wire->addHook('LazyCron::every30Minutes', null, 'myCronJob');

function myCronJob(HookEvent $event) {
    $secondsElapsed = $event->arguments(0);
    // runs roughly every 30 minutes
}
Intervals

All interval methods are hookable. The first time LazyCron runs it fires every interval to establish baselines, so expect all hooks to execute once immediately after installation.

MethodSecondsApproximate interval
every30Seconds3030 seconds
everyMinute601 minute
every2Minutes1202 minutes
every3Minutes1803 minutes
every4Minutes2404 minutes
every5Minutes3005 minutes
every10Minutes60010 minutes
every15Minutes90015 minutes
every30Minutes180030 minutes
every45Minutes270045 minutes
everyHour36001 hour
every2Hours72002 hours
every4Hours144004 hours
every6Hours216006 hours
every12Hours4320012 hours
everyDay864001 day
every2Days1728002 days
every4Days3456004 days
everyWeek6048001 week
every2Weeks12096002 weeks
every4Weeks24192004 weeks
Methods

execute()

execute(): void

Run all pending LazyCron jobs immediately. This is called automatically after page views unless cliOnly is enabled. You can also call it directly if you have a reference to the module instance.

$modules->get('LazyCron')->execute();

getTimeFuncs()

getTimeFuncs(): array

Return all supported interval methods keyed by seconds.

$funcs = $modules->get('LazyCron')->getTimeFuncs();
// [30 => 'every30Seconds', 60 => 'everyMinute', ...]

getTimeFuncName($seconds)

getTimeFuncName(int $seconds): string

Return the interval method whose period is closest to the given number of seconds.

$name = $modules->get('LazyCron')->getTimeFuncName(400); // 'every5Minutes'

getTimeFuncSeconds($timeFuncName)

getTimeFuncSeconds(string $timeFuncName): int

Return the number of seconds associated with an interval method name. The method name is case-sensitive.

$seconds = $modules->get('LazyCron')->getTimeFuncSeconds('everyHour'); // 3600

getCliCommands()

getCliCommands(): array

Return the CLI commands provided by this module (used by ProcessWire's CLI router).

$commands = $modules->get('LazyCron')->getCliCommands();
// ['run' => 'Run pending attached LazyCron jobs', 'list' => 'List current attached jobs']

executeCli(array $args)

executeCli(array $args): void

Dispatch a CLI command. Usually called by php index.php lazycron <command>.

$modules->get('LazyCron')->executeCli(['run']);
Properties
PropertyTypeDescription
cliOnlyboolWhen true, LazyCron does not run during HTTP requests. Use CLI/cron instead.
lastTimeintUnix timestamp of the most recent LazyCron execution.
lastResultstringSummary output from the most recent execution.
CLI

LazyCron registers the lazycron CLI namespace:

# Run pending jobs immediately
php index.php lazycron run

# List hooks currently attached to LazyCron intervals
php index.php lazycron list

When cliOnly is enabled, run is the only way (other than a real cron job hitting the site) to trigger LazyCron jobs.

Template-file jobs

As a convenience, LazyCron will include any PHP file placed in /site/templates/LazyCron/ whose name matches an interval method. For example, /site/templates/LazyCron/everyDay.php runs with the everyDay interval. All API variables ($pages, $config, etc.) are extracted into the file's scope.

// /site/templates/LazyCron/everyDay.php
$old = $pages->find('template=temp, created<' . (time() - 86400));
$pages->delete($old);

This is useful for quick, template-level cron jobs that do not warrant a custom module.

Notes
  • LazyCron uses a lock file (/site/assets/cache/LazyCronLock.cache) to prevent concurrent runs. The lock expires automatically after one hour if a previous run failed fatally.
  • State is stored in /site/assets/cache/LazyCron.cache.
  • Intervals are approximate when triggered by page views; use a real cron job or the CLI for precise scheduling.
  • The callback receives the actual elapsed seconds as its first argument.
  • LazyCron is an autoload module and is obtained with $modules->get('LazyCron').
  • Source file: wire/modules/System/LazyCron/LazyCron.module.

API reference: methods, properties, hooks

It is called 'lazy' because it's triggered by a pageview, so its accuracy executing at specific times will depend upon how many pageviews your site gets. So when a specified time is triggered, it's guaranteed to have been that length of time OR longer. This is fine for most cases. But here's how you make it NOT lazy:

Setup a real CRON job to pull a page from your site once per minute. Here is an example of a command that you could schedule to execute once per minute:

wget --quiet --no-cache -O - http://www.your-site.com > /dev/null

USAGE IN YOUR MODULES:

In your own module or template, add the function you want executed: public function myFunc(HookEvent $e) { echo "30 Minutes have passed!"; }

Then add the hook to it in your module's init() function: $this->addHook('LazyCron::every30Minutes', $this, 'myFunc');

PROCEDURAL USAGE (i.e. in templates):

create your hook function function myHook(HookEvent $e) { echo "30 Minutes have passed!"; }

add a hook to it: $wire->addHook('LazyCron::every30Minutes', null, 'myHook');

FUNCTIONS YOU CAN HOOK:

every30Seconds everyMinute every2Minutes every3Minutes every4Minutes every5Minutes every10Minutes every15Minutes every30Minutes every45Minutes everyHour every2Hours every4Hours every6Hours every12Hours everyDay every2Days every4Days everyWeek every2Weeks every4Weeks


Click any linked item for full usage details and examples. Hookable methods are indicated with the icon. In addition to those shown below, the LazyCron class also inherits all the methods and properties of: WireData and Wire.

Show class?     Show args?       Only hookable?    

Common

NameReturnSummary 
LazyCron::afterPageView(HookEvent $e)
None

Function triggered after every page view.

 
LazyCron::every10Minutes($seconds)
None
LazyCron::every12Hours($seconds)
None
LazyCron::every15Minutes($seconds)
None
LazyCron::every2Days($seconds)
None
LazyCron::every2Hours($seconds)
None
LazyCron::every2Minutes($seconds)
None
LazyCron::every2Weeks($seconds)
None
LazyCron::every30Minutes($seconds)
None
LazyCron::every30Seconds(int $seconds)
None

One or more of the following functions is called if the given interval has passed.

LazyCron::every3Minutes($seconds)
None
LazyCron::every45Minutes($seconds)
None
LazyCron::every4Days($seconds)
None
LazyCron::every4Hours($seconds)
None
LazyCron::every4Minutes($seconds)
None
LazyCron::every4Weeks($seconds)
None
LazyCron::every5Minutes($seconds)
None
LazyCron::every6Hours($seconds)
None
LazyCron::everyDay($seconds)
None
LazyCron::everyHour($seconds)
None
LazyCron::everyMinute($seconds)
None
LazyCron::everyWeek($seconds)
None
LazyCron::execute()
None

Execute lazycron jobs

 
LazyCron::executeCli(array $args)
None

Execute CLI command(s)

 
LazyCron::getCliCommands()
string

Get CLI commands

 
LazyCron::getTimeFuncName(int $seconds)
string

Get name of time function to hook for given number of seconds

 
LazyCron::getTimeFuncSeconds(string $timeFuncName)
int

Get number of seconds for given time function name or 0 if not found

 
LazyCron::getTimeFuncs()
string

Get hookable time functions that are allowed, indexed by number of seconds they use

 

Properties

NameReturnSummary 
LazyCron::cliOnly int bool When non-empty disallow running during http requests 
LazyCron::lastResult string Last run result 
LazyCron::lastTime int Unix timestamp when LazyCron last ran 

Additional methods and properties

In addition to the methods and properties above, LazyCron also inherits the methods and properties of these classes:

API reference based on ProcessWire core version 3.0.269