Laravel Scheduler Cron Not Working

Hello,

Using the standard template for a new Laravel app, the cron worker is not doing anything.

fly.toml

[processes]
  app = ""
  cron = "cron -f"
  worker = "php artisan queue:work"

Dockerfile (only section where Cron is set)

RUN composer install --optimize-autoloader --no-dev \
    && mkdir -p storage/logs \
    && php artisan optimize:clear \
    && chown -R webuser:webgroup /var/www/html \
    && sed -i 's/protected \$proxies/protected \$proxies = "*"/g' app/Http/Middleware/TrustProxies.php \
    && echo "MAILTO=\"\"\n* * * * * webuser /usr/bin/php /var/www/html/artisan schedule:run" > /etc/cron.d/laravel \
    && rm -rf /etc/cont-init.d/* \
    && cp docker/nginx-websockets.conf /etc/nginx/conf.d/websockets.conf \
    && cp docker/entrypoint.sh /entrypoint \
    && chmod +x /entrypoint

The logs for the cron instance shows Preparing to run: /entrypoint cron -f as root and then nothing happens. No jobs are ever scheduled. I know @fideloper-fly has worked on some issues with this. Any ideas?

Hi!

What’s your evidence that nothing is happening?

“No jobs are ever scheduled” implied that your cron tasks are creating queue jobs - is that right?

:one: You can use fly ssh console -s and select an instance to SSH into it. They aren’t necessarily named obviously but in my experience, the 2nd will be cron, and the third instance will be worker.

You can run commands like ps aux | grep cron to see that CRON is a running process or ps aux | grep artisan to see if the queue worker is running.

:two: Then perhaps head to /var/www/html and run php artisan schedule:run manually to see if it works.

:three: Also be sure to check fly logs to see if there’s any error output.

:question: Do you have env var setup for your queue connection? The default is sync, so they wouldn’t actually get run in a queue but whenever a job is dispatched (during the schedule:run command, if my guess is correct about the scheduled jobs firing jobs into the queue).

Be sure to check out the cron/queue docs to see if you missed anything, such as adjusting the php artisan queue:work command to work on the queue connection you need it to run on: Cron and Queues · Fly Docs

Hi - thanks for getting back to me so quickly.

The evidence is that there are no jobs being scheduled.

My queue instance logs sit at INFO Processing jobs from the [default] queue. unless I manually use fly ssh console -s to SSH into the cron instance, go to /var/www/html and run php artisan schedule:run manually. Then jobs get scheduled and processed, as shown by the queue instance’s logs.

My env var is set properly to database which is what I use for my jobs.

I read over the “Cron and Queues” Fly Docs but I don’t see anything that I missed.

Thanks! That all makes sense -

In my own instance just now, I did the following - which may help debug.

  1. SSH back into the cron instance (ps aux | grep cron will show if it’s the right instance, you’ll get a result there for cron -f)
  2. Edit /etc/cron.d/laravel and make it look like this (to add logging):
MAILTO=""
* * * * * webuser /usr/bin/php /var/www/html/artisan schedule:run >> /var/www/html/storage/logs/cron.log 2>&1

Wait a minute or 2, and then check /var/www/html/storage/logs/cron.log, you should see some output there. In a fresh Laravel app, I see:

root@3982c846:~# cat /var/www/html/storage/logs/cron.log

   INFO  No scheduled commands are ready to run.


   INFO  No scheduled commands are ready to run.


   INFO  No scheduled commands are ready to run.

:fire: Quick tip: Once you SSH in, run bash to start bash shell, which is a little friendlier/easier than the default sh

OK, so I followed your steps. (Thanks for the bash tip!)

I see that the commands are being run as evidenced by checking /var/www/html/storage/logs/cron.log:

  2022-10-30 03:26:01 Running ['artisan' app:fetchAlerts] in background  0ms DONE
  ⇂ ('/usr/bin/php8.1' 'artisan' app:fetchAlerts > '/dev/null' 2>&1 ; '/usr/bin/php8.1' 'artisan' schedule:finish "framework/schedule-2d925ba0962916a46ccd164ca1b9d78d7c96f7ad" "$?") > '/dev/null' 2>&1 & 

Interestingly though, there is nothing being added to the jobs table in the database and nothing is being logged by the worker, meaning jobs aren’t being dispatched to the right place. Note that this all works fine locally.

Running php artisan tinker and then running env("QUEUE_CONNECTION") returns "database", which is correct. It seems the cron instance is missing something…

I suspect other important env vars or secrets are not being picked up.

Here’s something annoying I haven’t found a great work around for yet:

cron doesn’t let Laravel read the VM environment variables that Fly sets.

However, the setup should be running artisan config:cache when the VM boots up, so your config should be in the confit cache.

Is your setup using env() directly in code instead of config()? (it’s okay and expected if config files use env(), but using env() elsewhere can lead to issues).

As soon as you mentioned artisan config:cache…

I SSH’d into the cron instance with fly ssh console -s, went to the app directory, and ran artisan config:cache. And a minute later my jobs started being scheduled and ran!

For some reason, this was clearly not being run when the VM booted. I’m not sure if the issue was with the Dockerfile or the entrypoint.sh script in the docker directory.

I created a new Laravel Fly app to see what was different, following the tutorial Fly.io Docs: Run a Laravel App and noticed the docker directory has been changed to .fly, and the scripts have been changed.

Long story short, I replaced my Dockerfile and docker directory with the Dockerfile and .fly directory from the tutorial and… everything started working!

Thanks a lot for your help @fideloper-fly :slight_smile:

I have gotten around this by running schedule:work in another process. It’s under a section called “Running scheduler locally” but it’s working fine so far.

[processes]
  app = ''
  worker = 'php artisan queue:work'
  scheduler = 'php artisan schedule:work'

I suspect other important env vars or secrets are not being picked up.

This has caused me a whole lot of headaches so I now try to avoid cron all together :grimacing:

it’s really lame behavior.

a .env file would fix it but creating the .env in fly’s (and heroku’s) model also seems annoying - although doable.

I wrote a guide at Crontab with Supercronic · Fly Docs that shows how to get cron running in a Fly container. I think it’s comprehensive enough where you won’t have to try to avoid it :smile:

Hi Brad, that’s great! One question about your post.

You wrote that this should be in your fly.toml:

[processes]
  web = "bin/rails fly:server"
  cron = "cron"

Shouldn’t the cron entry be something like supercronic crontab? As such:

[processes]
  web = "bin/rails fly:server"
  cron = "supercronic crontab"

I tried it with cron like you wrote in the article but that didn’t seem to work.

I haven’t played with this yet but if you get that working, send me a ping - I’d love to update the Laravel stuff with that if it solves the env issue.

I actually created a Laravel project with this yesterday, here’s a public repo showing what I did so far:

I didn’t thoroughly test it yet, but it seems to work fine!

EDIT: I just pushed some more changes that were still on my local machine that included running schedule:run.

Yep! You’re right, I think I feel asleep at the wheel. I’m going to update the docs. Thanks for running through them and sorry for sending you down a rabbit hole.

1 Like

To resolve the issue with your Laravel cron job not executing, ensure your setup follows these steps:

1. Verify SSH Access: Ensure your hosting provider grants SSH access, as deploying Laravel with tools like FileZilla is not recommended due to dependency management issues.

2. Correct Cron Configuration:

  • fly.toml: Make sure your cron command is correctly defined.
  • Dockerfile: Ensure the cron setup is properly integrated.

Here’s a sample Dockerfile section for setting up cron:

RUN composer install --optimize-autoloader --no-dev \
    && mkdir -p storage/logs \
    && php artisan optimize:clear \
    && chown -R webuser:webgroup /var/www/html \
    && sed -i 's/protected \$proxies/protected \$proxies = "*"/g' app/Http/Middleware/TrustProxies.php \
    && echo "MAILTO=\"\"\n* * * * * webuser /usr/bin/php /var/www/html/artisan schedule:run" > /etc/cron.d/laravel \
    && chmod 0644 /etc/cron.d/laravel \
    && crontab /etc/cron.d/laravel \
    && cp docker/nginx-websockets.conf /etc/nginx/conf.d/websockets.conf \
    && cp docker/entrypoint.sh /entrypoint \
    && chmod +x /entrypoint

3. Test Cron Manually:

  • Run the cron manually to ensure it’s working: php artisan schedule:run.
  • Check the logs in storage/logs/laravel.log to see if there are any errors.

4. Common Issues:

  • Ensure the cron service is running: service cron start.
  • Permissions: Ensure the cron file and directories have the correct permissions.
  • Check the crontab syntax and paths.

You can refer to this article for a detailed guide on Laravel cron jobs and troubleshooting.

1 Like

Hello @Jane_smith and welcome to Fly.io!

Thank you for sharing the steps above, they’re very helpful, specially the common issues part. Also! Here at Fly, we already have a cron daemon pre-configured to run the scheduler command, so running the scheduler on a Laravel Fly app is as quick as declaring the cron daemon as a Fly process in its fly.toml file:

[processes]
  app = ""
  cron = "cron -f"

Here’s the page you can read to learn more about the setup.

1 Like