Skip to content

Adds note for using cron #393

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 89 additions & 1 deletion docs/content/docs/4.laravel/2.laravel-task-scheduler.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,94 @@ Running a Laravel task scheduler with Docker can be a little different from the
## More detail
We need to run the [schedule:work](https://laravel.com/docs/11.x/scheduling#running-the-scheduler-locally) command from Laravel. Although the docs say "Running the scheduler locally", this is what we want in production. It will run the scheduler in the foreground and execute it every minute. You can configure your Laravel app for the exact time that a command should run through a [scheduled task](https://laravel.com/docs/11.x/scheduling#scheduling-artisan-commands).

## Using cron
Laraver versions prior to 8.x don't have the `schedule:work` command, as [noted by this PR](https://github.com/laravel/framework/pull/34618).

A non-invasive alternative is to incorporate the command manually in your application, which basically runs the scheduler each second on a loop.

::codepanel
---
label: A command that runs the Laravel Scheduler
---
```php
namespace App\Console;

use Illuminate\Console\Command;
use Illuminate\Support\Carbon;

class ScheduleWorkCommand extends Command
{
protected $name = 'schedule:work';
protected $description = 'Start the schedule worker';

public function handle()
{
$this->info('Starting the Schedule worker.');

while (true) {
if (Carbon::now()->second === 0) {
$this->call('schedule:run');
}

sleep(1);
}
}
}
```
::

If that is not an alternative, you will need to install `cron`, and add a cron entry to run the Laravel Scheduler each second.

The best place to prepare cron would be in the production image, or before installing your application inside the container. Alpine images use Busybox, which includes `crond` out of the box, so there is no need to install it.

::codepanel
---
label: Installing cron and adding a Laravel Scheduler entry
---
```dockerfile
# ... Prior build steps

# Ensure we're root to install and prepare cron.
USER root

# Set Laravel's Scheduler in the container default crontab file.
RUN printf "* * * * * www-data php /var/www/html/artisan schedule:run\n" >> /etc/crontab;

# Install cron on Debian
RUN apt-get update && apt-get -y --no-install-recommends install cron && \
rm -rf /var/lib/apit/lists/*

# Copy our app files as www-data (33:33)
COPY --chown=www-data:www-data . /var/www/html

# Ensure we are the unpriviledged www-data user
USER www-data

# Install the application
RUN composer install
```
::

In your Docker Compose file, you will need to call `cron` in the foreground. [On Debian](https://manpages.debian.org/bookworm/cron/cron.8.en.html), this is done with `/usr/sbin/cron -f -L 15`. On Alpine, [BusyBox's `crond`](https://busybox.net/downloads/BusyBox.html#crond) does the job as `/usr/sbin/crond -f -l 0`.

::code-panel
---
label: Calling the Laravel Scheduler through cron in Docker Compose File
---
```yaml
services:
php:
image: my/laravel-app
environment:
PHP_FPM_POOL_NAME: "my-app_php"

task:
image: my/laravel-app
command: ["/usr/sbin/cron", "-f", "-L", "15"]
environment:
PHP_FPM_POOL_NAME: "my-app_task"
```
::

## Examples
Here is a simplified example of how you can achieve this with Docker Compose:
Expand Down Expand Up @@ -88,4 +176,4 @@ class Kernel extends ConsoleKernel
}
}
```
::
::