• Resolved jamminjames

    (@jamminjames)


    Using the ‘as_enqueue_async_action’ hook, all the jobs get stuck in ‘past-due’ status and never run. If I click on “Run”, it completes just fine.

    Our site is pinged every minute via console.cron-job.org, all other cron jobs run fine. I checked the log there and it is working.

    I tried deactivating all other plugins, no change.

    How can I troubleshoot this issue? Thanks for any help.

Viewing 12 replies - 1 through 12 (of 12 total)
  • Plugin Support Shameem – a11n

    (@shameemreza)

    Hi @jamminjames

    Thanks for the detailed info. I know how frustrating this kind of thing can be.

    If your async actions are getting stuck in past-due but run fine manually, it usually means the async runner isn’t being triggered properly. Even if your site’s cron is firing every minute, Action Scheduler’s async queue uses a separate request behind the scenes:

    /wp-admin/admin-ajax.php?action=as_async_request_queue_runner

    If that request gets blocked or fails silently, the jobs will just sit there.

    Few thing I’d suggest checking:

    • Try visiting that URL in your browser while logged in. Does it run or show an error?
    • Look in your server error logs for anything related to admin-ajax.php
    • Disable any security/firewall plugins temporarily (Wordfence, iThemes, etc.) and test again.

    That said, if you want to trigger the async queue manually for testing, here’s a quick snippet you can run once from a custom plugin or via WP CLI:

    do_action( 'action_scheduler_run_queue', 'Async Request' );

    Let me know if this helps or if you have any follow-up questions.

    Thread Starter jamminjames

    (@jamminjames)

    Thanks for the response. I’ve searched all the server logs, no errors are showing. When I run the /wp-admin/admin-ajax.php?action=as_async_request_queue_runner command and check the console, it does indeed show a “403 (Forbidden)” error. We have an Nginx server, and I’ve looked at all our .conf files, and can find no “deny all” rules for the wp-admin folder nor the admin-ajax.php file. I tried pausing Cloudflare and deactivating Wordfence. It’s a mystery. Any other suggestions on how to track down the reason for the 403?

    You say I can run do_action( 'action_scheduler_run_queue', 'Async Request' ); for testing. Can I just run that every time we want to use async? We’re using it for downloading about 20-30 large images, once every week.

    Plugin Support Shameem – a11n

    (@shameemreza)

    Hey @jamminjames

    Thanks for checking all that and sharing additional details.

    That URL /wp-admin/admin-ajax.php?action=as_async_request_queue_runner needs to be hit by anonymous requests. A 403 usually means something (server, plugin, firewall) is blocking it. Since you’ve ruled out Cloudflare and Wordfence, here are a few more places to check:

    • Look for any custom code or mu-plugins restricting access to admin-ajax.php. Especially anything that calls is_user_logged_in() and dies for anonymous users.
    • If your host runs a WAF (even separate from Cloudflare), it may be blocking non-browser traffic to admin-ajax. Worth checking with them.
    • Try hitting that URL using cURL with a standard user agent:
    curl -A "Mozilla/5.0" -I "https://yoursite.com/wp-admin/admin-ajax.php?action=as_async_request_queue_runner"

    If that gets a 200, but your cron job doesn’t, it’s likely a user-agent or header issue.

    Can I just run that every time we want to use async?

    Yes, calling do_action( 'action_scheduler_run_queue', 'Async Request' ); manually works as a workaround. You can even hook it into a scheduled action or CLI command. For example:

    if ( defined( 'WP_CLI' ) && WP_CLI ) {
    add_action( 'init', function() {
    do_action( 'action_scheduler_run_queue', 'Async Request' );
    } );
    }

    Keep in mind that it runs jobs in the current process, so if those image downloads are heavy, PHP timeouts could kick in. For that, wp action-scheduler run via CLI is safer.

    Let me know what you find in those config checks.

    Thread Starter jamminjames

    (@jamminjames)

    When I run the curl command, I get:

    curl -A "Mozilla/5.0" -I "https://www.humortimes.com/wp-admin/admin-ajax.php?action=as_async_request_queue_runner"
    HTTP/1.1 403 Forbidden
    Date: Wed, 21 May 2025 05:21:26 GMT
    Content-Type: text/html; charset=UTF-8
    Connection: keep-alive
    Server: cloudflare
    Vary: Accept-Encoding
    X-Powered-By: PHP/8.2.28
    Cf-Edge-Cache: cache,platform=wordpress
    X-Robots-Tag: noindex
    X-Content-Type-Options: nosniff
    Referrer-Policy: strict-origin-when-cross-origin
    X-Frame-Options: SAMEORIGIN
    Expires: Wed, 11 Jan 1984 05:00:00 GMT
    Cache-Control: no-cache, must-revalidate, max-age=0, no-store, private
    Nel: {"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}
    Cf-Cache-Status: DYNAMIC
    Report-To: {"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=DsWIvWJ58Yuw6k%2FUis44gIJqpc2bNX7LW4RhWDDfAn%2FDspaJ6pBMEYdw2qJ85Xr4VwvrBKl0X4Ub2tlOpU2cpqWRJ1RFKTWKNCVlo2W4ize1rWnoTxQvzF7S"}]}
    Set-Cookie: wp_wpfileupload_6b6aa56ad25b06ea7cd5e7d129c445ef=fDxsf8DBsNkjxPw5gPMQfSFmSY6G6rdK; Path=/; Max-Age=172800; Expires=Fri, 23 May 2025 05:21:24 GMT
    CF-RAY: 9431a14d3da4642f-SJC
    alt-svc: h3=":443"; ma=86400

    I get the 403, as you can see. I also get something curious: Set-Cookie: wp_wpfileupload_6b6aa56ad25b06ea7cd5e7d129c445ef=fDxsf8DBsNkjxPw5gPMQfSFmSY6G6rdK; Path=/; Max-Age=172800; Expires=Fri, 23 May 2025 05:21:24 GMT

    That looks like it belongs to a plugin called “WordPress File Upload Pro.” Could the cookie interfere somehow? I have tried /wp-admin/admin-ajax.php?action=as_async_request_queue_runner with all plugins deactivated, still get 403.

    One thing I noticed is that if I deactivate the custom plugin that creates the as_enqueue_async_action and has the callback, the past-due actions go through, with a “no callback” error, of course. Does the fact that they go through at that point mean anything? It seems it wouldn’t, since running the jobs manually works without any errors, so I wouldn’t think the plugin files were the problem.

    I also flushed the entire Cloudflare cache, Redis object cache and fastcgi cache. We’re not using a cache plugin.

    You said that calling do_action( 'action_scheduler_run_queue', 'Async Request' ); manually works, but that it runs jobs in the current process, so if those image downloads are heavy, PHP timeouts could kick in. That’s not the case if we can run as_enqueue_async_action successfully the usual way, right? That’s the whole reason I want to use it, I read that it would help avoid PHP timeouts.

    Plugin Support Shameem – a11n

    (@shameemreza)

    Hi @jamminjames

    That looks like it belongs to a plugin called “WordPress File Upload Pro.” Could the cookie interfere somehow? 

    It (wp_wpfileupload_*) shouldn’t interfere with Action Scheduler’s async requests. That cookie is specific to file upload functionality.

    One thing I noticed is that if I deactivate the custom plugin that creates the as_enqueue_async_action and has the callback, the past-due actions go through, with a “no callback” error, of course. Does the fact that they go through at that point mean anything?

    Yes, it is quite telling. This suggests the issue isn’t with Action Scheduler’s core async request mechanism but rather with how the async request interacts with your custom plugin’s callback registration.

    That’s not the case if we can run as_enqueue_async_action successfully the usual way, right? 

    Yes, you’re correct. When running this way:

    • It runs in the current process, so PHP timeouts could be an issue for your image downloads.
    • It doesn’t have the benefits of Action Scheduler’s async processing.

    For troubleshooting, you could try this temporary solution to bypass the async request mechanism:

    add_filter( 'action_scheduler_allow_async_request_runner', '__return_false' );

    This filter will force Action Scheduler to use the WP Cron runner instead of async requests. However, please note:

    1. This is a temporary debugging step, not a long-term solution.
    2. It will affect ALL async actions in your site, not just your image downloads.
    3. Long-running tasks may still hit PHP timeouts since they’ll run in the main process.

    If this filter resolves the issue, it confirms the problem is specifically with the async request mechanism rather than the action registration or callback. However, given your need to handle large image downloads, you should still work on fixing the root cause of the 403 errors rather than entirely disabling async requests.

    That said, would you be able to share:

    • When exactly do the actions get stuck in past-due? Right after creation or after some time?
    • Are there any patterns in which images fail vs succeed?
    • Do you see any relevant entries in your server’s error logs when this happens?

    This will help me better understand the root cause rather than just working around it.

    Thread Starter jamminjames

    (@jamminjames)

    There are a lot of other things not related to the async call that are getting stuck, including one called action_scheduler/migration_hook. The others use regular scheduling (not async), so that suggests there’s more to this than just the callback for the as_enqueue_async_action.

    I did remove the async past-due actions, and then ran our code again. They immediately go to past-due again. Then I removed all the past-due actions, and the next time action_scheduler/migration_hook tried to run (every minute?), it went into past-due again. This is without me running the async action.

    I wish the logs were more helpful, but I have not been able to find anything. Ours is a dedicated Nginx server that I work on directly. Can you give me some keywords that I could search for that should be produced in the log entries? Which logs to you expect them to be in? WordPress error log, Nginx, php-fpm, anything in the database I could look for?

    • This reply was modified 9 months, 3 weeks ago by jamminjames.
    Thread Starter jamminjames

    (@jamminjames)

    Okay, I decided to deactivate the two custom plugins I had that were using the scheduler, then reinstall Action Scheduler. Then I reactivated the original plugin, which never had any problems (doesn’t use as_enqueue_async_action), and scheduled an action for 5 minutes. It ran fine and did not go to past-due. None of the other actions that were in there are getting stuck either.

    So, as you said, the problem seems to be with the as_enqueue_async_action callback code in the newer plugin. I will go over it and see what I can figure out.

    I know it’s asking a lot, but if I get stuck, can I send you the relevant parts of the code to have you take a look?

    Plugin Support Shameem – a11n

    (@shameemreza)

    Hi @jamminjames

    That’s great to hear things are moving again!

    Since it’s pointing to something in the newer plugin’s callback code, I’ll mark the thread as resolved for now. You can always reopen it.

    That said, writing, sharing, reviewing, or debugging custom code is outside our support scope, but if you get stuck, feel free to share a snippet. I can’t promise full code review, but I’ll do my best to point you in the right direction.

    You can also drop your question in the WooCommerce Slack community. Many of our developers hang out there and may be able to help further.

    Let me know how it goes.

    Thread Starter jamminjames

    (@jamminjames)

    Okay, it’s working now, hallelujah! I think the offending code may have been something I had put in that was supposed to be commented out:

    add_filter( 'action_scheduler_queue_runner_time_limit', 'eg_increase_time_limit' )

    I thought it was something I might use later, but it was left in, with the useless ‘eg_increase_time_limit’, which I’m thinking may have totally screwed up the timer.

    At least that’s something you can ask about if anyone else has these weird symptoms.

    Is there a hook to tell when a list of async actions have been completed?

    Btw, another quick question, the “Complete” list is getting very big. Is that something that should be cleared out once in a while? Seems like it would clog the db after a while. Is there a way to set a limit on how long a list it keeps?

    Thanks for your help and patience!

    • This reply was modified 9 months, 3 weeks ago by jamminjames.
    • This reply was modified 9 months, 3 weeks ago by jamminjames.
    Plugin Support Shameem – a11n

    (@shameemreza)

    Hi @jamminjames

    So glad to hear it’s working now! That stray filter definitely sounds like the culprit.

    Is there a hook to tell when a list of async actions have been completed?

    Yes, Action Scheduler fires this hook when an individual action is marked complete:

    do_action( 'action_scheduler_completed_action', $action_id );

    There’s no built-in hook for when a group of async actions finishes, so if you’re tracking batches, you’d need custom logic to handle that.

    another quick question, the “Complete” list is getting very big. Is that something that should be cleared out once in a while?

    Completed actions can pile up over time. By default, they’re kept for 30 days. You can reduce that with:

    add_filter( 'action_scheduler_retention_period', function() {
    return WEEK_IN_SECONDS; // or whatever duration fits
    } );

    You can also try this too: https://gist.github.com/shameemreza/e65052121d9de46de4030c5aa7abe2cc

    add_filter( 'action_scheduler_retention_period', 'wc_action_scheduler_purge' );
    /**
    * Change Action Scheduler default purge to 1 week
    */
    function wc_action_scheduler_purge() {
    return WEEK_IN_SECONDS;
    }

    That said, I appreciate you sharing your findings. This will help others running into the same 403 mystery. If the plugin’s been helpful, a quick review would go a long way! You can add your feedback here: https://wordpress.org/support/plugin/action-scheduler/reviews/#new-post

    Feel free to create a new topic if you need further help with Action Scheduler.

    Thanks!

    Thread Starter jamminjames

    (@jamminjames)

    There’s no built-in hook for when a group of async actions finishes, so if you’re tracking batches, you’d need custom logic to handle that.

    Any hints on how to do that? I don’t see how we could know on the server side when the async actions are done, if there’s no hook for it.

    Plugin Support Shameem – a11n

    (@shameemreza)

    Hi @jamminjames

    One common approach is to track the action IDs when scheduling them, then use the action_scheduler_completed_action hook to monitor which ones are done. Once all the IDs you tracked are completed, you can trigger your own “batch complete” logic.

    It takes a bit of setup, but it’s a reliable way to simulate batch tracking.

    Let me know if this helps or if you have any follow-up questions.

Viewing 12 replies - 1 through 12 (of 12 total)

The topic ‘Async actions get stuck in ‘past-due’’ is closed to new replies.