# Timers

> For the complete documentation index, see [llms.txt](https://docs.temporal.io/llms.txt).
> Any documentation page is available as raw Markdown by appending `.md` to its URL.
> For related questions, query https://docs.temporal.io/api/retrieve?q=<question>&jtb=<job-to-be-done>&src=md-page&agent=<your-name> (no auth; returns JSON `{content, source_url, page_url}`, with `source_url` pointing to Markdown for docs pages). Don't include personal data or credentials.

> A Workflow sets durable Timers for fixed periods using sleep() or timer(). Timers are persisted, ensuring execution continues after downtime, using minimal resources.

## What is a Timer? 

A Workflow can set a durable Timer for a fixed time period.
In some SDKs, the function is called `sleep()`, and in others, it's called `timer()`.

A Workflow can sleep for months.
Timers are persisted, so even if your Worker or Temporal Service is down when the time period completes, as soon as your Worker and Temporal Service are back up, the `sleep()` call will resolve and your code will continue executing.

Sleeping is a resource-light operation: it does not tie up the process, and you can run millions of Timers off a single Worker.

## Asynchronous design patterns in TypeScript 

The real value of `sleep` and `condition` is in knowing how to use them to model asynchronous business logic.
Here are some examples we use the most; we welcome more if you can think of them!

### Race Timers 

Use `Promise.race` with Timers to dynamically adjust delays.

<!--SNIPSTART typescript-timers-racing-timers-->
[typescript-sandbox/src/workflows/timers/racing-timers.ts](https://github.com/temporalio/documentation-sdk-code-examples/blob/main/typescript-sandbox/src/workflows/timers/racing-timers.ts)
```ts
export async function processOrderWorkflow({
  orderProcessingMS,
  sendDelayedEmailTimeoutMS,
}: ProcessOrderOptions): Promise<void> {
  let processing = true;
  const processOrderPromise = processOrder(orderProcessingMS).then(() => {
    processing = false;
  });

  await Promise.race([processOrderPromise, sleep(sendDelayedEmailTimeoutMS)]);

  if (processing) {
    await sendNotificationEmail();
    await processOrderPromise;
  }
}
```
<!--SNIPEND-->

### Race Signals 

Use `Promise.race` with Signals and Triggers to have a promise resolve at the earlier of either system time or human intervention.

<!--SNIPSTART typescript-timers-racing-signals-->
[typescript-sandbox/src/workflows/timers/racing-signals.ts](https://github.com/temporalio/documentation-sdk-code-examples/blob/main/typescript-sandbox/src/workflows/timers/racing-signals.ts)
```ts
import { defineSignal, setHandler, sleep, Trigger } from '@temporalio/workflow';

const userInteraction = new Trigger<boolean>();
export const completeUserInteraction = defineSignal('completeUserInteraction');

export async function yourWorkflow(userId: string) {
  setHandler(completeUserInteraction, () => userInteraction.resolve(true)); // programmatic resolve
  const userInteracted = await Promise.race([userInteraction, sleep('30 days')]);
  if (!userInteracted) {
    await sendReminderEmail(userId);
  }
}
```
<!--SNIPEND-->

You can invert this to create a reminder pattern where the promise resolves _if_ no Signal is received.

> **⚠️ Caution:**
> Antipattern: Racing sleep.then
>
> Be careful when racing a chained `sleep`.
> This might cause bugs because the chained `.then` will still continue to execute.
>
> <!--SNIPSTART typescript-timers-sleep-then-antipattern {"enable_code_dedenting": true}-->
> [typescript-sandbox/src/workflows/timers/sleep-then-antipattern.ts](https://github.com/temporalio/documentation-sdk-code-examples/blob/main/typescript-sandbox/src/workflows/timers/sleep-then-antipattern.ts)
> ```ts
> await Promise.race([
>   sleep('5s').then(() => (status = 'timed_out')),
>   somethingElse.then(() => (status = 'processed')),
> ]);
>
> if (status === 'processed') await complete(); // takes more than 5 seconds
> // status = timed_out
> ```
> <!--SNIPEND-->
>

### Build an updatable Timer 

Here is how you can build an updatable Timer with `condition`:

<!--SNIPSTART typescript-timers-updatable-timer-usage-->
[typescript-sandbox/src/workflows/timers/countdown.ts](https://github.com/temporalio/documentation-sdk-code-examples/blob/main/typescript-sandbox/src/workflows/timers/countdown.ts)
```ts
import * as wf from '@temporalio/workflow';

export const setDeadlineSignal = wf.defineSignal<[number]>('setDeadline');
export const timeLeftQuery = wf.defineQuery<number>('timeLeft');

// usage
export async function countdownWorkflow(): Promise<void> {
  const target = Date.now() + 24 * 60 * 60 * 1000; // 1 day!!!
  const timer = new UpdatableTimer(target);
  console.log('timer set for: ' + new Date(target).toString());
  wf.setHandler(setDeadlineSignal, (deadline) => {
    // send in new deadlines via Signal
    timer.deadline = deadline;
    console.log('timer now set for: ' + new Date(deadline).toString());
  });
  wf.setHandler(timeLeftQuery, () => timer.deadline - Date.now());
  await timer; // if you send in a signal with a new time, this timer will resolve earlier!
  console.log('countdown done!');
}
```
<!--SNIPEND-->

This is available in the third-party package [`temporal-time-utils`](https://www.npmjs.com/package/temporal-time-utils#user-content-updatabletimer), where you can also see the implementation:

<!--SNIPSTART typescript-timers-updatable-timer-implementation-->
[typescript-sandbox/src/workflows/timers/updatable-timer.ts](https://github.com/temporalio/documentation-sdk-code-examples/blob/main/typescript-sandbox/src/workflows/timers/updatable-timer.ts)
```ts
// implementation
export class UpdatableTimer implements PromiseLike<void> {
  deadlineUpdated = false;
  #deadline: number;

  constructor(deadline: number) {
    this.#deadline = deadline;
  }

  private async run(): Promise<void> {
    /* eslint-disable no-constant-condition */
    while (true) {
      this.deadlineUpdated = false;
      if (!(await wf.condition(() => this.deadlineUpdated, this.#deadline - Date.now()))) {
        break;
      }
    }
  }

  then<TResult1 = void, TResult2 = never>(
    onfulfilled?: (value: void) => TResult1 | PromiseLike<TResult1>,
    onrejected?: (reason: any) => TResult2 | PromiseLike<TResult2>,
  ): PromiseLike<TResult1 | TResult2> {
    return this.run().then(onfulfilled, onrejected);
  }

  set deadline(value: number) {
    this.#deadline = value;
    this.deadlineUpdated = true;
  }

  get deadline(): number {
    return this.#deadline;
  }
}
```
<!--SNIPEND-->
