# cron (/docs/core/cron)

cron is a tiny server-side scheduler shipped with ESX Legacy. Other resources
register a callback for a time of day (hour and minute) and cron calls it once
every day at that time. Official addons use it, for example `esx_society` for
salaries and `esx_vehicleshop` for rental payments.

## Overview [#overview]

| | |
| --- | --- |
| Resource | `cron` |
| Side | Server only |
| Dependencies | None |
| Config | None |
| Required | Only when a resource uses `cron:runAt` (esx_society and esx_vehicleshop do) |

## cron:runAt [#cronrunat]

The only API is a server-side local event.

```lua
TriggerEvent("cron:runAt", h, m, cb)
```

| Name | Type | Description |
| --- | --- | --- |
| `h` | `number` | Hour, 0-23, in server local time. |
| `m` | `number` | Minute, 0-59. |
| `cb` | `function` | Called as `cb(d, h, m)`. A callable table (with `__call`) also works. |

Callback arguments:

| Name | Type | Description |
| --- | --- | --- |
| `d` | `number` | Weekday from `os.date("*t").wday`: 1 = Sunday, 2 = Monday, ..., 7 = Saturday. |
| `h` | `number` | The hour you registered. |
| `m` | `number` | The minute you registered. |

Wrong argument types fail with an `assert` that names the invoking resource.

### Examples [#examples]

```lua title="server/main.lua"
-- Every day at 05:10
TriggerEvent("cron:runAt", 5, 10, function(d, h, m)
    print(("Daily cleanup at %02d:%02d"):format(h, m))
    MySQL.update("DELETE FROM my_logs WHERE created_at < NOW() - INTERVAL 30 DAY")
end)
```

```lua title="server/main.lua"
-- Every Monday at 18:30
local MONDAY <const> = 2

TriggerEvent("cron:runAt", 18, 30, function(d)
    if d ~= MONDAY then return end
    print("Weekly payout")
end)
```

```lua title="server/main.lua"
-- Every 6 hours: register several times
for _, hour in ipairs({ 0, 6, 12, 18 }) do
    TriggerEvent("cron:runAt", hour, 0, function()
        print("Six-hour task")
    end)
end
```

## How scheduling works [#how-scheduling-works]

- cron checks once per minute, aligned to the start of the minute.
- On each new minute it computes every job's most recent scheduled time (today,
  or yesterday if today's time is still ahead) and runs the job if that time is
  newer than the previous check. A short server hitch therefore does not skip a
  job.
- Jobs do **not** catch up after a restart. A task scheduled for 05:10 does not
  run if the server was offline at 05:10.
- Errors in a callback are caught and printed as
  `cron job at HH:MM errored, skipping it`; other jobs keep running.

## Common issues [#common-issues]

- **Weekday check never matches.** The official README uses `d == 1` for
  Monday. In Lua `wday` 1 is Sunday; Monday is `2`.
- **Task runs at the wrong hour.** The server's timezone differs from yours.
  Check `os.date()` in the server console.
- **Errors after restarting a resource.** Jobs cannot be removed. When you
  restart a resource that registered a job, the old callback reference stays
  registered and errors every day, next to the new job the restarted resource
  registers. The error is harmless, but a full server restart cleans it up.
- **Jobs stop after restarting cron.** Jobs live in cron's memory. Restarting
  `cron` alone drops every job; the resources that registered them must be
  restarted too.
- **Registering from the client.** `cron:runAt` is a server-only local event;
  it does nothing on the client and cannot be triggered over the network.

## Related [#related]

- [Core resources overview](/docs/core)
- [Server functions](/docs/es_extended/server/functions)
- [esx_society](/docs/addons/esx_society)
- [oxmysql guide](/docs/guides/oxmysql)
