> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# Taakplanning

> Leer hoe je met de scheduler van Laravel terugkerende taken elegant beheert.

## Wat is taakplanning

Traditioneel moest je voor elke terugkerende taak op de server handmatig een cron-entry schrijven.
Bij die aanpak staat de planningsdefinitie echter buiten je broncode: er is geen versiebeheer mogelijk en voor elke controle of wijziging moet je via SSH inloggen.

Met de scheduler van Laravel kun je **je planning vloeiend definiëren binnen je applicatie**.
Op de server volstaat één enkele cron-entry, en de planningsdefinitie wordt samen met je code onder versiebeheer gehouden.

De standaardstijl is om de planning te definiëren in `routes/console.php`.

```php theme={null}
<?php

use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schedule;

Schedule::call(function () {
    DB::table('recent_users')->delete();
})->daily();
```

<Info>
  Met het Artisan-commando `schedule:list` bekijk je een overzicht van de gedefinieerde taken en hun volgende geplande uitvoertijd.

  ```shell theme={null}
  php artisan schedule:list
  ```
</Info>

### Uitvoeringsflow van de scheduler

```mermaid theme={null}
flowchart TD
    A["* * * * * artisan schedule:run<br>(elke minuut aangeroepen door cron)"] --> B["Console Kernel"]
    B --> C["Aanroep van de schedule()-methode"]
    C --> D["Geregistreerde taken één voor één evalueren"]
    D --> E{"Komt de cron-expressie overeen<br>met de huidige tijd?"}
    E -->|"Geen match"| F["Overslaan"]
    E -->|"Match"| G{"Controle van when / skip /<br>environments-voorwaarden"}
    G -->|"Voorwaarden niet voldaan"| F
    G -->|"Voorwaarden voldaan"| H{"Onderhouds-<br>modus actief?"}
    H -->|"Normale modus"| I["Taak uitvoeren<br>(before-hook → taak → after-hook)"]
    H -->|"Onderhoudsmodus"| J{"Is evenInMaintenanceMode()<br>ingesteld?"}
    J -->|"Ja"| I
    J -->|"Nee"| F
```

## Een planning definiëren

Je definieert de planning in `routes/console.php`.
Het kan ook via de `withSchedule`-methode in `bootstrap/app.php`.

```php theme={null}
// bootstrap/app.php
use Illuminate\Console\Scheduling\Schedule;

->withSchedule(function (Schedule $schedule) {
    $schedule->call(new DeleteRecentUsers)->daily();
})
```

## Soorten planbare taken

### Artisan-commando's plannen

Met de `command`-methode plan je Artisan-commando's in.
Je kunt ze opgeven via de commandonaam of de klassenaam.

```php theme={null}
use App\Console\Commands\SendEmailsCommand;
use Illuminate\Support\Facades\Schedule;

// Opgeven via commandonaam
Schedule::command('emails:send Taylor --force')->daily();

// Opgeven via klassenaam (argumenten als array)
Schedule::command(SendEmailsCommand::class, ['Taylor', '--force'])->daily();
```

Ook aan Artisan-commando's die als closure zijn gedefinieerd, kun je direct na de definitie planningsmethoden koppelen.

```php theme={null}
Artisan::command('delete:recent-users', function () {
    DB::table('recent_users')->delete();
})->purpose('Delete recent users')->daily();
```

### Queue-jobs plannen

Met de `job`-methode plan je [queue-jobs](/nl/queues) in.
Een handige manier om jobs op de queue te zetten zonder een closure te gebruiken.

```php theme={null}
use App\Jobs\Heartbeat;
use Illuminate\Support\Facades\Schedule;

Schedule::job(new Heartbeat)->everyFiveMinutes();
```

Je kunt ook de queuenaam en de verbinding opgeven.

```php theme={null}
// Dispatchen naar de "heartbeats"-queue via de "sqs"-verbinding
Schedule::job(new Heartbeat, 'heartbeats', 'sqs')->everyFiveMinutes();
```

### Shell-commando's plannen

Met de `exec`-methode voer je OS-commando's uit.

```php theme={null}
use Illuminate\Support\Facades\Schedule;

Schedule::exec('node /home/forge/script.js')->daily();
```

### Closures plannen

Met de `call`-methode plan je een willekeurige PHP-closure in.

```php theme={null}
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schedule;

Schedule::call(function () {
    DB::table('recent_users')->delete();
})->daily();
```

Je kunt ook invocable objecten met een `__invoke`-methode doorgeven.

```php theme={null}
Schedule::call(new DeleteRecentUsers)->daily();
```

## De frequentie instellen

### Belangrijkste frequentiemethoden

Hieronder de meest gebruikte frequentiemethoden.

| Methode                    | Beschrijving                                        |
| -------------------------- | --------------------------------------------------- |
| `->everySecond()`          | Elke seconde uitvoeren                              |
| `->everyMinute()`          | Elke minuut uitvoeren                               |
| `->everyFiveMinutes()`     | Elke 5 minuten uitvoeren                            |
| `->everyFifteenMinutes()`  | Elke 15 minuten uitvoeren                           |
| `->everyThirtyMinutes()`   | Elke 30 minuten uitvoeren                           |
| `->hourly()`               | Elk uur uitvoeren                                   |
| `->hourlyAt(17)`           | Elk uur op minuut 17 uitvoeren                      |
| `->daily()`                | Elke dag om 0:00 uitvoeren                          |
| `->dailyAt('13:00')`       | Elke dag om 13:00 uitvoeren                         |
| `->twiceDaily(1, 13)`      | Elke dag om 1:00 en 13:00 uitvoeren                 |
| `->weekly()`               | Elke zondag om 0:00 uitvoeren                       |
| `->weeklyOn(1, '8:00')`    | Elke maandag om 8:00 uitvoeren                      |
| `->monthly()`              | Elke 1e van de maand om 0:00 uitvoeren              |
| `->monthlyOn(4, '15:00')`  | Elke 4e van de maand om 15:00 uitvoeren             |
| `->quarterly()`            | Op de eerste dag van elk kwartaal om 0:00 uitvoeren |
| `->yearly()`               | Elk jaar op 1 januari om 0:00 uitvoeren             |
| `->timezone('Asia/Tokyo')` | Tijdzone opgeven                                    |

### Rechtstreeks een cron-expressie opgeven

Met de `cron`-methode kun je ook rechtstreeks een cron-expressie opgeven.

```php theme={null}
use Illuminate\Support\Facades\Schedule;

Schedule::command('emails:send')->cron('0 9 * * *'); // Elke dag om 9:00 uitvoeren
```

### Frequentie en weekdagen combineren

Door frequentiemethoden te combineren met weekdagbeperkingen maak je fijnmazigere planningen.

```php theme={null}
use Illuminate\Support\Facades\Schedule;

// Elke maandag om 13:00 uitvoeren
Schedule::call(function () {
    // ...
})->weekly()->mondays()->at('13:00');

// Op werkdagen elk uur uitvoeren tussen 8:00 en 17:00
Schedule::command('foo')
    ->weekdays()
    ->hourly()
    ->timezone('Asia/Tokyo')
    ->between('8:00', '17:00');
```

### De tijdzone instellen

Met de `timezone`-methode geef je per taak een tijdzone op.

```php theme={null}
use Illuminate\Support\Facades\Schedule;

Schedule::command('report:generate')
    ->timezone('Asia/Tokyo')
    ->at('9:00');
```

Wil je één gemeenschappelijke tijdzone voor alle taken, gebruik dan `schedule_timezone` in `config/app.php`.

```php theme={null}
// config/app.php
'schedule_timezone' => 'Asia/Tokyo',
```

<Warning>
  Bij tijdzones met zomertijd kan een taak op het omschakelmoment twee keer worden uitgevoerd of juist helemaal niet.
  Gebruik waar mogelijk UTC.
</Warning>

## Voorwaardelijke beperkingen

### when / skip

`when` voert de taak alleen uit als de closure `true` teruggeeft.
`skip` doet het omgekeerde: geeft de closure `true` terug, dan wordt de taak overgeslagen.

```php theme={null}
use Illuminate\Support\Facades\Schedule;

// Alleen uitvoeren als de voorwaarde true is
Schedule::command('emails:send')->daily()->when(function () {
    return true;
});

// Overslaan als de voorwaarde true is
Schedule::command('emails:send')->daily()->skip(function () {
    return true;
});
```

### environments

Met de `environments`-methode beperk je de uitvoering tot bepaalde omgevingen.

```php theme={null}
Schedule::command('emails:send')
    ->daily()
    ->environments(['staging', 'production']);
```

### Tijdsbeperkingen

Met `between` / `unlessBetween` beperk je de tijdvakken waarin de taak draait.

```php theme={null}
// Alleen uitvoeren tussen 7:00 en 22:00
Schedule::command('emails:send')
    ->hourly()
    ->between('7:00', '22:00');

// Niet uitvoeren tussen 23:00 en 4:00
Schedule::command('emails:send')
    ->hourly()
    ->unlessBetween('23:00', '4:00');
```

### Weekdagbeperkingen

| Methode                         | Beschrijving                                     |
| ------------------------------- | ------------------------------------------------ |
| `->weekdays()`                  | Alleen werkdagen                                 |
| `->weekends()`                  | Alleen in het weekend                            |
| `->mondays()` t/m `->sundays()` | Alleen op een specifieke dag                     |
| `->days([0, 3])`                | Meerdere dagen, bijv. zondag (0) en woensdag (3) |

```php theme={null}
use Illuminate\Support\Facades;
use Illuminate\Console\Scheduling\Schedule;

Facades\Schedule::command('emails:send')
    ->hourly()
    ->days([Schedule::SUNDAY, Schedule::WEDNESDAY]);
```

## Overlap voorkomen

Standaard start de volgende uitvoering ook als de vorige taak nog bezig is.
Met `withoutOverlapping` laat je de volgende uitvoering wachten tot de vorige is afgerond.

```php theme={null}
use Illuminate\Support\Facades\Schedule;

Schedule::command('emails:send')->withoutOverlapping();
```

Je kunt ook de geldigheidsduur van de lock (in minuten) opgeven. De standaard is 24 uur.

```php theme={null}
// De lock vervalt na 10 minuten
Schedule::command('emails:send')->withoutOverlapping(10);
```

<Info>
  `withoutOverlapping` beheert de locks via de cache van je applicatie.
  Loopt een taak door een onverwacht probleem vast, dan kun je de lock opheffen met `schedule:clear-cache`.

  ```shell theme={null}
  php artisan schedule:clear-cache
  ```
</Info>

## Uitvoering op meerdere servers beheersen

Draait de scheduler op meerdere servers, dan kun je met `onOneServer` een taak op slechts één server laten uitvoeren.

```php theme={null}
use Illuminate\Support\Facades\Schedule;

Schedule::command('report:generate')
    ->fridays()
    ->at('17:00')
    ->onOneServer();
```

<Warning>
  Voor deze functie moet de standaardcachedriver van je applicatie zijn ingesteld op `database`, `memcached`, `dynamodb` of `redis`, en moeten alle servers met dezelfde cacheserver verbonden zijn.
</Warning>

### Flow van gedistribueerde uitvoering met onOneServer()

```mermaid theme={null}
flowchart TD
    A["artisan schedule:run wordt gelijktijdig<br>op meerdere servers uitgevoerd"] --> B["Server 1"]
    A --> C["Server 2"]
    A --> D["Server 3"]

    B --> E["Poging om een atomaire lock te verkrijgen<br>op de gedeelde cacheserver"]
    C --> E
    D --> E

    E -->|"Lock verkregen (de eerste server)"| F["Taak uitvoeren"]
    E -->|"Lock niet verkregen (overige servers)"| G["Taak overslaan"]

    F --> H["Lock vrijgeven na afronding"]
```

## Taken groeperen

Wil je dezelfde instellingen op meerdere taken toepassen, dan kun je ze bundelen met de `group`-methode.

```php theme={null}
use Illuminate\Support\Facades\Schedule;

Schedule::daily()
    ->onOneServer()
    ->timezone('Asia/Tokyo')
    ->group(function () {
        Schedule::command('emails:send --force');
        Schedule::command('emails:prune');
    });
```

## Uitvoeren op de achtergrond

Taken die op hetzelfde tijdstip gepland staan, worden standaard na elkaar uitgevoerd in de volgorde van definitie.
Een langdurige taak vertraagt dan de start van de volgende taken.
Met `runInBackground` voer je taken parallel op de achtergrond uit.

```php theme={null}
use Illuminate\Support\Facades\Schedule;

Schedule::command('analytics:report')
    ->daily()
    ->runInBackground();
```

<Warning>
  `runInBackground` is alleen te gebruiken met de methoden `command` en `exec`.
</Warning>

## Onderhoudsmodus

Wanneer je applicatie in onderhoudsmodus staat, worden geplande taken niet uitgevoerd.
Wil je een taak toch gedwongen laten draaien tijdens de onderhoudsmodus, gebruik dan `evenInMaintenanceMode`.

```php theme={null}
Schedule::command('emails:send')->evenInMaintenanceMode();
```

### Flow bij onderhoudsmodus

```mermaid theme={null}
flowchart TD
    A["artisan schedule:run"] --> B{"Staat de app in<br>onderhoudsmodus?<br>(artisan down)"}
    B -->|"Normale modus"| C["Taak normaal uitvoeren"]
    B -->|"Onderhoudsmodus"| D{"Heeft de taak<br>evenInMaintenanceMode()<br>ingesteld?"}
    D -->|"Ja"| C
    D -->|"Nee"| E["Taak overslaan"]
```

## De scheduler pauzeren

Je kunt de scheduler pauzeren zonder code te wijzigen.

```shell theme={null}
# Scheduler pauzeren
php artisan schedule:pause

# Scheduler hervatten
php artisan schedule:continue
```

Wil je tijdens een pauze bepaalde taken tóch laten doorlopen, gebruik dan `evenWhenPaused`.
Handig voor taken die ook tijdens onderhoud moeten blijven draaien, zoals healthchecks en systeemmonitoring.

```php theme={null}
Schedule::command('emails:send')->evenWhenPaused();
```

## Output afhandelen

### Output naar een bestand

Met `sendOutputTo` sla je de output van een taak op in een bestand.

```php theme={null}
use Illuminate\Support\Facades\Schedule;

Schedule::command('emails:send')
    ->daily()
    ->sendOutputTo(storage_path('logs/emails-send.log'));
```

Met `appendOutputTo` voeg je de output toe aan een bestaand bestand.

```php theme={null}
Schedule::command('emails:send')
    ->daily()
    ->appendOutputTo(storage_path('logs/emails-send.log'));
```

### Output per e-mail

Met `emailOutputTo` verstuur je de output van een taak per e-mail.
Hiervoor moet vooraf de [mailconfiguratie](/nl/mail) van Laravel zijn ingesteld.

```php theme={null}
Schedule::command('report:generate')
    ->daily()
    ->sendOutputTo($filePath)
    ->emailOutputTo('admin@example.com');
```

Wil je alleen bij een mislukking een e-mail versturen, gebruik dan `emailOutputOnFailure`.

```php theme={null}
Schedule::command('report:generate')
    ->daily()
    ->emailOutputOnFailure('admin@example.com');
```

## Taakhooks

Met de methoden `before` / `after` voer je logica uit vóór en na een taak.

```php theme={null}
use Illuminate\Support\Facades\Schedule;

Schedule::command('emails:send')
    ->daily()
    ->before(function () {
        // Logica vóór de taak
    })
    ->after(function () {
        // Logica na de taak
    });
```

Hooks voor succes en falen definieer je met `onSuccess` / `onFailure`.

```php theme={null}
use Illuminate\Support\Stringable;

Schedule::command('emails:send')
    ->daily()
    ->onSuccess(function (Stringable $output) {
        // Logica bij succes
    })
    ->onFailure(function (Stringable $output) {
        // Logica bij falen
    });
```

## Deployen naar de server

<Steps>
  <Step title="De cron-entry toevoegen">
    Voeg slechts deze ene regel toe aan de crontab van je server en de Laravel-scheduler draait elke minuut.

    ```shell theme={null}
    * * * * * cd /path-to-your-project && php artisan schedule:run >> /dev/null 2>&1
    ```

    Bewerken kan met het commando `crontab -e`.
  </Step>

  <Step title="De werking van de scheduler controleren">
    Bekijk de lijst met gedefinieerde taken en hun volgende uitvoertijd.

    ```shell theme={null}
    php artisan schedule:list
    ```
  </Step>
</Steps>

<Tip>
  Met [Laravel Cloud](https://cloud.laravel.com) beheer je geplande taken zonder cron-configuratie.
</Tip>

### Uitvoeren tijdens lokale ontwikkeling

Lokaal kun je zonder cron de scheduler continu laten draaien met het commando `schedule:work`.

```shell theme={null}
php artisan schedule:work
```

Dit commando draait op de voorgrond en roept de scheduler elke minuut aan. Het blijft draaien totdat je stopt met `Ctrl+C`.

### Sub-minuutplanning (frequenties onder één minuut)

Bij gewone cron is één minuut de kleinste eenheid, maar in Laravel kun je ook plannen op secondeniveau.

```php theme={null}
use Illuminate\Support\Facades\Schedule;

Schedule::call(function () {
    DB::table('recent_users')->delete();
})->everySecond();
```

Als er sub-minuuttaken zijn gedefinieerd, blijft `schedule:run` tot het einde van die minuut draaien om alle sub-minuuttaken te verwerken.

<Tip>
  Delegeer het werk van sub-minuuttaken bij voorkeur aan queue-jobs of achtergrondcommando's.
  Als de taak zelf lang duurt, lopen de volgende sub-minuuttaken vertraging op.
</Tip>

Om een lopende `schedule:run` te onderbreken tijdens een deployment, voeg je dit toe aan je deployscript:

```shell theme={null}
php artisan schedule:interrupt
```

## Veelgebruikte commando's op een rij

```shell theme={null}
# Takenlijst tonen
php artisan schedule:list

# Scheduler handmatig uitvoeren (het commando dat cron op de server aanroept)
php artisan schedule:run

# Continu draaien voor lokale ontwikkeling
php artisan schedule:work

# Scheduler pauzeren
php artisan schedule:pause

# Scheduler hervatten
php artisan schedule:continue

# Anti-overlap-locks wissen
php artisan schedule:clear-cache

# Uitvoering van sub-minuuttaken onderbreken (bij deployment)
php artisan schedule:interrupt
```


## Related topics

- [Bottutorial - Laravel Bluesky](/nl/packages/laravel-bluesky/bot-tutorial.md)
- [Artisan-console](/nl/artisan.md)
