# Cron Framework

Ce répertoire est un **wrapper générique autour de `node-cron`**. Il ne connaît aucune tâche spécifique — les modules et features enregistrent leurs propres jobs. Ajouter un nouveau job ne nécessite jamais de modifier `src/core/cron/`.

---

## Structure

```
src/core/cron/
└── index.js   schedule, stop, stopAll, trigger, validate, isRunning, getJobs, getStatus
```

---

## Import

```js
import { schedule, stop, trigger } from '@zen/core/cron';
```

---

## API

### `schedule(name, cronSchedule, handler, options?)`

Enregistre un job. Si un job du même nom existe déjà, il est stoppé et remplacé.

```js
schedule('daily-report', '0 9 * * *', async () => {
  await sendReport();
});

schedule('every-5min', '*/5 * * * *', async () => {
  await syncData();
}, { timezone: 'America/New_York', runOnInit: true });
```

| Paramètre | Type | Description |
|-----------|------|-------------|
| `name` | `string` | Nom unique du job |
| `cronSchedule` | `string` | Expression cron (5 ou 6 champs) |
| `handler` | `async Function` | Fonction exécutée à chaque déclenchement |
| `options.timezone` | `string` | Timezone IANA (défaut : `ZEN_TIMEZONE` ou `America/Toronto`) |
| `options.runOnInit` | `boolean` | Exécuter immédiatement à l'enregistrement (défaut : `false`) |

Retourne l'instance `node-cron` task.

---

### `stop(name)`

Stoppe et supprime un job par son nom. Retourne `true` si le job existait, `false` sinon.

### `stopAll()`

Stoppe et supprime tous les jobs enregistrés.

### `trigger(name)`

Déclenche manuellement un job sans attendre son prochain tick. Lève une `Error` si le job n'existe pas.

```js
await trigger('daily-report');
```

### `validate(expression)`

Valide une expression cron. Retourne `boolean`.

### `isRunning(name)`

Vérifie si un job est actuellement enregistré. Retourne `boolean`.

### `getJobs()`

Retourne la liste des noms de tous les jobs enregistrés (`string[]`).

### `getStatus()`

Retourne les métadonnées de tous les jobs enregistrés.

```js
{
  'daily-report': {
    schedule: '0 9 * * *',
    timezone: 'America/Toronto',
    registeredAt: '2026-04-24T09:00:00.000Z'
  }
}
```

---

## Enregistrer un job depuis un module

Les jobs vivent **avec leur feature ou module**, pas dans le framework. Enregistrer un job dans `initializeZen()` (`src/shared/lib/init.js`) :

```js
// src/modules/mymodule/cron.js
import { schedule } from '@zen/core/cron';

export function registerCronJobs() {
  schedule('mymodule-sync', '*/15 * * * *', async () => {
    await syncMyModule();
  });
}
```

```js
// src/shared/lib/init.js
import { registerCronJobs } from '../../modules/mymodule/cron.js';

registerCronJobs();
```

---

## Comportement Hot-Reload

Les jobs sont stockés dans `globalThis[Symbol.for('__ZEN_CRON_JOBS__')]` — un store partagé qui survit aux invalidations de cache de modules de Next.js. Un job enregistré deux fois (hot-reload) remplace silencieusement l'ancien plutôt que de créer un doublon.

---

## Gestion des erreurs

Les erreurs levées par un handler sont interceptées et loguées via `fail()` — elles ne font jamais crasher le processus.

```
✗ Cron daily-report: Connection timeout
```
