# Schedulers

> Run TypeScript on a schedule in API Maker - intervals from every second to every year or a cron expression, a time zone per interval, one run per cluster with failover, a timeout, versions, and start, stop or run now from the admin panel.

Source: https://docs.apimaker.dev/v1/docs/apis-all/schedulers/user-created-schedulers-api.html

A scheduler is a TypeScript function which runs on a schedule : every few seconds, every night at two, on the first of the month, or on any cron expression, in the time zone you pick. On a cluster of servers each run happens once, on one server, and moves to another one when a server goes down.

> Diagram : Schedulers on a cluster : every interval runs once, on one server, spread over the servers, with failover
>
> Schedulers on a cluster of three API Maker servers : each scheduler has intervals with a time zone ; at each tick exactly one server of the cluster runs it, the schedulers are spread over the servers, and when a server goes down another one picks its schedulers up.

## Create a scheduler

`API Info → Schedulers`, then **+**.

| Field | Meaning |
|---|---|
| Name | Unique in the account, can not change later (it names the folder in Git). Label can. |
| Timeout in minutes | The run is stopped after this long. |
| Code | The function, with the global object `g`. |
| Intervals | One or more, each with a time interval, a time zone and an active switch. |
| Active | The master switch of the scheduler. |
| Run on native process | Run in API Maker itself instead of the sandbox. |
| Save response in log | Keep what the run returned in the log table. |

## The code

```typescript
import * as T from 'types';
import * as db from 'db-interfaces';

async function main(g: T.IAMGlobal) {
    const stale = await g.sys.db.query({
        instance: 'mongodb', database: 'shop', collection: 'carts',
        find: { updated_at: { $lt: new Date(Date.now() - 7 * 86400000).toISOString() } },
        select: '_id',
    });
    const removed = await g.sys.db.removeByQuery({
        instance: 'mongodb', database: 'shop', collection: 'carts',
        find: { _id: { $in: stale.map(c => c._id) } },
    });
    g.logger.log(`${removed.deletedRowsCount} carts removed`);
    return { removed: removed.deletedRowsCount };
}
module.exports = main;
```

- The same `g` as a custom API, without a request : `g.req.body` and `g.req.query` are empty. Use `g.shared` and the [cache](https://docs.apimaker.dev/v1/examples/sys/cache/setKey.html) to keep state between runs.

## Intervals

| Group | Choices |
|---|---|
| Seconds | every second, 5, 10, 15, 30 seconds |
| Minutes | every minute, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30 minutes |
| Hours | every hour, 2, 3, 4, 6, 8, 12 hours |
| Days | every day, 2, 3, 5, 10, 15 days |
| Working days | Monday to Friday at 11:30 |
| Months | every month, 2, 3, 4, 6 months |
| Year | every year |
| Custom | a cron expression |

- Each interval has its **time zone** : `Asia/Kolkata`, `Europe/Paris`, `UTC`… A scheduler with two intervals runs both.
- Each interval has its own active switch, so one can be paused without touching the other.

### Custom cron expressions

Six fields, seconds first : `second minute hour day-of-month month day-of-week`. Five fields work too (the seconds default to `0`).

| Expression | Runs |
|---|---|
| `0 0 22 * * 1-5` | at 22:00, Monday to Friday |
| `0 15 14 1 * *` | at 14:15 on the first of every month |
| `*/30 * * * * *` | every 30 seconds |
| `0 0 */6 * * *` | every 6 hours |

## On a cluster

- **Once per tick.** Whatever the number of API Maker servers, an interval runs once : the servers agree through Redis which one runs each scheduler, and a scheduler already running is not started again.
- **Spread out.** The schedulers of an account are spread over the servers instead of all running on one.
- **Failover.** When a server stops, the schedulers it ran are picked up by the others.
- **Safe deployments.** A Git pull or a deployment does not interrupt a run in progress ; the next run uses the new code.

## Start, stop, run now

- The **Active** switch starts and stops a scheduler right away, on every server : stop a misbehaving job in production in one click.
- **Run now** from the [API testing page](https://docs.apimaker.dev/v1/docs/features/developer-tools.html#api-testing-page) (pick the scheduler, send) runs it once, outside its schedule, and shows the result and the logs.
- The Schedulers page marks a scheduler running now on a node, and one whose intervals are all switched off : it never runs. **Clone** copies a scheduler.
- Versions : keep several versions of the code, one active.

## Good to know

- A [log profile](https://docs.apimaker.dev/v1/docs/logs/log-profile.html) records every run with its duration and its output.
- Schedulers are files in Git (`src/Schedulers/<name>/`) and deploy with a pull. Their active state and intervals travel with them.
- A scheduler which needs more than its timeout should split the work : page through the rows and keep a cursor in the cache.
- Groups grant schedulers to API users for the testing page and the run API.
