> For the complete documentation index, see [llms.txt](https://docs.skail.dev/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.skail.dev/construa/conceitos/tempo-e-agendamento.md).

# Tempo e agendamento

Como uma function espera um tempo sem segurar nada, o que acontece se a aplicação for reiniciada durante a espera, e por que a hora atual vem de um command.

## Delay é um checkpoint com hora marcada

Um delay de 24 horas não bloqueia thread nem mantém um timer no processo. O runtime grava um passo no histórico da execução com o prazo, pede ao skail para acordar a execução naquele momento e libera a execução: ela hiberna. Quando o prazo chega, o skail entrega a execução de novo à sua aplicação, o runtime reexecuta a function, encontra o passo do delay concluído e segue para o próximo `await`.

<figure><img src="https://1898946878-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsJmS5ILPG5x2x5j0WyiV%2Fuploads%2FtfzG19NxM4nblXPngQ1R%2Fap-tempo-agendamento.svg?alt=media" alt="Um delay de 24 horas grava o prazo e a execução hiberna no skail. No prazo, a aplicação está fora do ar, então a execução espera e é entregue quando a aplicação volta: o delay não se perde, só a retomada atrasa. Na retomada, a execução segue para o próximo await."><figcaption></figcaption></figure>

Há três formas de escrever o mesmo delay:

* com uma duração (em TypeScript, em milissegundos);
* com um número de segundos;
* com um número de minutos.

Funcionam para segundos, minutos, horas, dias e semanas. Um delay de 30 dias custa o mesmo que um de 30 segundos enquanto espera: nada.

## O que acontece durante a espera

A aplicação pode ser reiniciada, escalada, atualizada ou movida de servidor. A execução hibernada não está nela; está no skail, com o prazo marcado. Quando o prazo chega e a aplicação está rodando, a execução retoma. Se a aplicação estiver fora do ar no momento, a execução espera e é entregue quando a aplicação voltar; o delay não se perde, só a retomada atrasa.

{% hint style="warning" %}
Se o código publicado mudou durante a espera, a retomada usa o código novo. Isso funciona enquanto a sequência de `await`s da function for a mesma; se não for, o replay diverge. Ver [Versionamento de código com execuções em andamento](/construa/conceitos/versoes-com-execucoes-em-andamento.md).
{% endhint %}

## A hora atual vem de um command

Dentro de uma function, ler a hora atual é proibido: o valor muda entre a primeira execução e cada replay, e um cálculo de prazo feito com ele produz um delay diferente a cada vez. A forma correta é ler o relógio em um command, que executa uma vez e grava o valor:

{% tabs %}
{% tab title="C#" %}
{% code lineNumbers="true" %}

```csharp
[SkailFunction]
public async SkailTask LembrarVencimento(Fatura fatura)
{
    var agora = await ObterDataAtual();                          // gravado; igual em todo replay
    var ateOLembrete = fatura.Vencimento.AddDays(-3) - agora;
    if (ateOLembrete > TimeSpan.Zero)
        await SkailTask.Delay(ateOLembrete);
    await EnviarLembrete(fatura.Id);
}

[SkailCommand]
public async SkailTask<DateTime> ObterDataAtual() => await Task.FromResult(DateTime.UtcNow);
```

{% endcode %}
{% endtab %}

{% tab title="TypeScript" %}
{% code lineNumbers="true" %}

```typescript
import { Skail, SkailCommand, SkailFunction } from "@skail/runtime";

interface Fatura {
  id: string;
  vencimento: string;
}

const UM_DIA_MS = 24 * 60 * 60 * 1000;

export class Faturas {
  @SkailFunction()
  async lembrarVencimento(fatura: Fatura): Promise<void> {
    const agora = await this.obterDataAtual(); // gravado; igual em todo replay
    const ateOLembreteMs = new Date(fatura.vencimento).getTime() - 3 * UM_DIA_MS - new Date(agora).getTime();
    if (ateOLembreteMs > 0) await Skail.delay(ateOLembreteMs);
    await this.enviarLembrete(fatura.id);
  }

  @SkailCommand()
  async obterDataAtual(): Promise<string> {
    return new Date().toISOString();
  }

  @SkailCommand()
  async enviarLembrete(faturaId: string): Promise<void> {
    /* ... */
  }
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

{% hint style="info" %}
Repare que o delay é calculado a partir de um valor gravado, então o passo do delay é sempre o mesmo no replay. Se a fatura já vence em menos de três dias, o `if` evita um delay negativo.
{% endhint %}

## Delay como prazo de uma espera

O uso mais comum do delay é dar prazo a uma espera por evento. A function espera o evento ou o delay, o que vier primeiro, e trata o timeout. O padrão completo está em [Como esperar com timeout](/construa/como-fazer/esperar-um-evento-com-prazo.md).

## Agendar para uma data

Não existe "execute às 8h de segunda" como primitiva. O equivalente é calcular o intervalo até a data desejada a partir de um relógio lido em command e usar um delay. Para rotinas recorrentes, uma function que faz o trabalho, espera até a próxima data e chama a si mesma inicia um novo ciclo; para rotinas de longa duração, veja o item sobre laços em [Antipadrões](/construa/como-fazer/padroes-e-antipadroes/antipadroes-o-que-nao-fazer-e-por-que.md).

## Próximos passos

A [referência do delay](/referencia/sdk-csharp/delay.md) traz as três formas. [Timeout e prazo](/construa/como-fazer/padroes-e-antipadroes/timeout-e-prazo.md) e [Régua de lembretes](/construa/como-fazer/padroes-e-antipadroes/regua-de-lembretes.md) são os dois padrões que mais usam tempo. [Hibernação e retomada](/construa/conceitos/hibernacao-e-retomada.md) explica o que acontece com a execução enquanto o prazo não chega.
