Keeping the Action Scheduler database tables cleaned out and free of excess unnecessary data can help your WordPress website run better and faster. You could remove the unnecessary data manually, but why not do it automatically by implementing the code in this blog post?
What is Action Scheduler?
Action Scheduler is a tool developed and maintained by Automattic. It is typically included as a library with plugins such as WooCommerce, MailPoet, Solid Backups (formerly known as BackupBuddy), and many others. It can also be installed as a plugin, but that’s not as common.
Plugins use Action Scheduler to schedule all kinds of background processing tasks, from backups to recurring payments to general housekeeping tasks. Your WordPress website is probably using Action Scheduler for something, and if it is you can find it in the WordPress menu under Tools -> Scheduled Actions.
Action Scheduler and your database
Action Scheduler adds four tables to your database:
- actionscheduler_actions
- actionscheduler_claims
- actionscheduler_groups
- actionscheduler_logs
Left to its own devices, Action Scheduler cleans the actionscheduler_actions and actionscheduler_logs tables every minute, removing any actions and their associated logs that have been in those tables longer than thirty-one days, and it does this in batches of twenty actions at a time.
The problem I had (and you may also have) is that by default it only cleans out actions (and their associated logs) that have the status “complete” or “canceled.” Actions marked as “failed” remain in the tables indefinitely. I suppose that makes some sense, as it gives the site admin a chance to look into why those actions failed. However, some or many of those failed actions are often corrected when their associated plugins are updated, and therefore they no longer need to be kept in the database.
The ever-zealous MailPoet plugin
An issue I had with several websites is that MailPoet, the email newsletter and marketing plugin, has two actions that run approximately every two minutes, mailpoet/cron/daemon-trigger and mailpoet/cron/daemon-run.
As I understand it, mailpoet/cron/daemon-trigger tells mailpoet/cron/daemon-run to run, and when mailpoet/cron/daemon-run is finished, which may be a few seconds to a few minutes later, mailpoet/cron/daemon-trigger is again scheduled for two minutes after that.
This isn’t exact due to the variance in run times for mailpoet/cron/daemon-run, but somewhere in the neighborhood of one thousand completed actions are added to the database every day, and if the scheduler retains completed actions for thirty-one days, which it does by default, then that amounts to thousands of completed actions and their logs continually sitting in your database. Each one of those MailPoet actions adds three additional rows to the actionscheduler_logs table.
This screenshot of an Action Scheduler admin page shows the two MailPoet actions, their associated log entries, and their overall effect on the database with 23,006 actions perpetually taking up space in the database for this particular website example.
This all adds up to MiBs of useless data sitting in your database taking up space, making your database bloated and potentially slowing down your website. (A mebibyte (MiB) is a multiple of 1,024 and a megabyte (MB) is a multiple of 1,000. Databases, at least the MySQL databases I use, use MiBs instead of MBs.)
The two screenshots below from PhpMyAdmin show the Action Scheduler database tables before and after implementing the code I’ve documented in the code section further down this post.
Why does this matter?
As websites continue to get more and more complex, their databases tend to grow along with that complexity. The size and complexity of your database can and does affect the speed of your website for your users.
There are support threads on the WordPress forums and elsewhere of people dealing with Action Scheduler database tables filled with GBs of unnecessary data.
One issue I ran into was with backups made by Solid Backups (formerly BackupBuddy) scheduled to run in the background. There are times when Solid Backups fails to complete a scheduled or manual backup due to the size of a database. Keeping the size of the database as small as possible can only help in that regard.
Another issue with Solid Backups is that the default advanced settings for that plugin have it running a PHP runtime test and a PHP memory test on a weekly basis. By design these two tests will always result in a “failed” status in Action Scheduler—and by default, Action Scheduler does not remove “failed” actions.
How to improve Action Scheduler – the code
Gist – Automatically clean Action Scheduler database tables and improve your WordPress website
The code explained
The first filter adds the “failed” status to the default Action Scheduler statuses of “complete” and “canceled” that are removed or purged during the routine cleanup process.
The second filter changes the number of actions that are purged each time the cleanup process runs. The default batch size is 20, but I’ve changed that to 100. You could use any number you want, but the larger the number the longer it will take, and you risk running out of server memory if you go too big. You could also use a larger number for the initial cleanup process and then change it back to a number like 100 when you have matters under control.
There’s another filter available that I’ve opted not to use that allows you to change the retention period from thirty-one days to whatever interval you prefer. I decided to leave that interval alone except for actions related to specific plugins, which is what the next bit of code does.
The rest of the code consists of two functions that work together to let you customize which actions are purged and how often, if you don’t want to wait for Action Scheduler’s default thirty-one day retention period.
The default retention period in my code is one day (86400 seconds), and in my working example I’ve left that default retention period for Rank Math SEO actions and set the retention period for MailPoet actions to three days (259200 seconds). Both the actionscheduler_actions and actionscheduler_logs tables are purged of the actions and their logs in one operation.
The functions are hooked to the wp_loaded action hook, which fires after WordPress is fully loaded. Anytime a page loads, either on the front end or in the admin, the code will run. So the code runs “automatically” as long as your website is getting some traffic, or you or another user is accessing the back end of the website.
Where to put this code
Add the code to a core functionality plugin (the best choice), its own plugin, or your theme’s functions.php file.
Modify the code to fit your needs and desires, as well as any other plugins you may be using that are filling up your Action Scheduler database tables with unnecessary data.
And finally, make a backup of your website and its database before introducing any new code or significant changes.
kamil says
Thanks for code and explanation, but what’s the purpose of running it on every page load? Scheduling a cron job to do it once a week should be more than enough
John Sundberg says
You certainly could use wp_cron like you suggest, and that may have crossed my mind when I was working up this code, but hooking it to wp_loaded is simpler and more dependable.
Running the code once a week may not be often enough for plugins like MailPoet, which adds approximately 1,000 completed actions to the database every day. If you were only running it once each week you’d need to increase the batch size to somewhere in the thousands, and then you’re running the risk of the server running out of memory and the clean-up process not completing.