Cron and Queues
You may need to run Laravel’s scheduler (via cron) or queue workers.
The best way is to use the processes configuration.
This allows you to segment your application into “groups”. Each “group” can run an instance of your code base with a specific use case (web server, cron tasks, queue worker).
If you used
fly launchto create your Laravel application, all of this should work without further modification to the Docker setup.
We can start the
cron daemon, which is pre-configured to run
php artisan schedule:run.
To enable this, edit your
fly.toml file and add a
[processes] app = "" cron = "cron -f"
app = "" is needed (with an empty string!) to keep a process group for your application serving web requests.
We created an additional process group
cron = "cron -f". This tells the VM to run the cron daemon rather than start the web server.
Dockerfile to add additional cron definitions to
/etc/cron.d if you need. The
cron -f command will load any cron definitions found in any files in that location.
We can start an instance of our queue worker by adding another process. In this example, we’ll add a
worker process group in addition to
[processes] app = "" cron = "cron -f" worker = "php artisan queue:listen"
Note that you may want to expand on the
queue:listen command. For example, you could run
php artisan queue:listen sqs --sleep=3 --tries=3 --max-time=3600 to use the
sqs driver and determine other behaviors.
There’s a few bits to explain about the above.
Internally, the things defined in the
[processes] section are commands to run when the application instance is run.
In Docker terminology, these are the Commands (
CMD) being sent to the Entrypoint (
ENTRYPOINT) as defined in the
That’s why the
app process group has a command of an empty string! We want the Entrypoint script to run without passing it any additional commands. The Entrypoint script will then perform it’s default behavior of starting Nginx/PHP-FPM to serve web requests.
The commands we defined are run relative to the Laravel project root, which is
/var/www/html by default. This is configured in the
Dockerfile used to setup the application.
Lastly, don’t forget that Fly.io builds a Docker image, and then converts that to a micro-VM run on Fly’s hardware.
[[services]] section of the
fly.toml should already contain the line
processes = ["app"], telling Fly to apply the service config to the application VM serving web requests. That will expose public ports and set health checks as you would want for the public-facing application.
[[services]] http_checks =  internal_port = 8080 processes = ["app"] # see! it's here! protocol = "tcp" script_checks =  # and so on ...
The queue and cron application instances don’t need to expose public ports and don’t support tcp-based health checks. Thus, we do not define any
services for them.
You can scale the process groups out separately. For example, this will create 2
app instances (load balanced automatically) and 4 queue worker instances.
fly scale count app=2 worker=4
Check the docs on processes for more examples on scaling separately (e.g. scaling server size and regions per process group).