I'm writing a blog post about the cron system in Moodle 4.2 because I wanted to understand all the settings!
Cron overview
Normally, you set the cron script to be launched once per minute. These runs can happen in parallel (one keeps running while the next one starts), which is the only way that multiple tasks can run at once. So if you have just started the server, then only one task can run, but a minute later there will be another cron launch and now two tasks can run, and so on.
Processing within a single cron runner
1 If we are not already at the concurrency limit for scheduled tasks (task_scheduled_concurrency_limit - default 3):
a Get the next scheduled task and run it
b Repeat from (a) until there are no tasks due or we hit the scheduled task runner lifetime (task_scheduled_max_runtime - default 30 min)
2 If we are not already at the concurrency limit for adhoc tasks (task_adhoc_concurrency_limit - default 3):
a Get the next adhoc task and run it
b Repeat from (a) until there are no tasks due or we hit the adhoc task runner lifetime (task_adhoc_mask_runtime - default 30 min)
3 If we haven't already reached the keep alive limit (cron_keepalive - default 3 minutes), wait a second and repeat from (1).
Implications of default settings
No tasks
If there are no tasks to run, on default settings there will usually (after server startup) be 3 instances of the cron runner at a time, because of the 3 minute keep alive. (The one that started 3 minutes ago has just ended; the one that started 2 minutes ago and the one that started one minute ago are still running; a new one has just atarted.)
Each second, all 3 tasks will acquire the scheduled lock, check for scheduled tasks, release the lock, acquire and adhoc lock, check for adhoc tasks, release the lock.
Infinite tasks
If there sre infinite tasks of both types, on default settings there will usually be 6 instances of the cron runner (=total of concurrency limits). At any given time, three of the instances will be dedicated to scheduled tasks (because of the task_scheduled_maxruntime) while three will be dedicated to adhoc tasks (because of hitting the scheduled concurrency limit, then running until the task_adhoc_maxruntime).
Server startup with infinite tasks
On server startup, at default settings it will be 3 minutes before any adhoc tasks are processed; the first three runners will be dedicated to scheduled tasks, then the next three will be dedicated to adhoc tasks.
Impact of changing settings
task_scheduled_concurrency_limit, task_adhoc_concurrency_limit
These are the biggies. Be careful with these settings.
Low: If you turn down these settings, the cron server will require less server memory at busiest times, and there will be less database/storage impact rom task processing. This could be important because some tasks (GDPR, backup) can occupy quite a lot of both resources.
If you set it low you need to be careful you have also applied other limits to individual tasks (by configuring scheduled tasks to run only when needed, and by seting the limits so that adhoc tasks don't run too many at once, e.g. $CFG->task_concurrency_limit_default = 1 or something more specific). Otherwise it's very easy for a task to eat all the concurrency meaning no other tasks of that type can run. For example, if a GDPR data export task takes 12 hours to run, and you have concurrency limit of 2, then 2 of those would eat it.
High: You need to make sure the cron server has enough memory to cope, and the database can cope with the processing without reducing performance for student requests..
Overall: Depends on your cron server performance, especially memory, and also how heavyweight the tasks you normally run are.
task_scheduled_max_runtime, task_adhoc_max_runtime:
Low: If you set these settings lower it will stop a single task runner from being dedicated to a single type of task (scheduled for 30 mins if there is a slot available, then adhoc for 30 mins) in cases where there are lots of tasks to run. Instead the task runner will alternate between each type of task more quickly.
This will mean it keeps acquiring and releasing locks, so there might be a slight performance cost.
I'm not clear there is any particular benefit in doing this.
If you set these settings very low then it might be harder to reach the concurrency settings. For instance, if you set these to 1 minute each and cron_keepalive at default 3 minutes, and there are no long-running tasks, then the task runner will always exit after 4 minutes (1+1, 1+1), so there cannot be more than 4 tasks running in parallel. (In practice if you need many parallel tasks then you probably do have long-running tasks so this might not be a problem.)
High: If you set the settings very high then it will keep a single runner operating for a long time (up to the sum of both settings). This is probably a bad idea because you might as well exit the PHP process periodically (it could clear up any memory that got allocated, any static variables that got set, generally anything that might get encrusted). There's another one along in a minute!
You don't need to set this high if a single task takes a long time, the task runner won't exit mid-task anyway.
Overall: The default is probably OK but a lower value like 10 minutes (= max runner lifetime approx. 20 minutes assuming there are no long-running tasks) might make more sense.
cron_keepalive:
Low: If you reduce this setting it will mean fewer task runners waiting when the system is idle. For example, if you set this to 60 seconds, there will usually be just one cron runner (if there are no tasks to run). This is both a sliight performance advantage (less locking etc) and also a disadvantage in terms of how quickly the system can scale up to run multiple tasks when busy, bearing in mind it can only add one parallel task per minute.
For example, if the system is idle with one task runner, and then at least three scheduled tasks totalling at least three minutes of work become due at once, no ad-hoc tasks will run for the next three minutes as the existing idle runner and the next two task runners will be occupied with scheduled tasks.
If you set to less than a minute, then even if the system is idle, users will have to wait for the next minute for an adhoc task to run, rather than it happening immediately
High: If you increase the setting then more task runners will wait idle. I don't think there is likely to be very much of a case for increasing it beyond the default though..
Overall: You probably want it set to at least 60 seconds. If there are no big concerns over delay in parallel tasks starting, then 60 seconds is probably sufficient, otherwise maybe it needs to be higher.