> 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/funcionalidades/sdk/externalevents.md).

# ExternalEvents

Nem toda continuação de uma função depende só de tempo ou de outras tarefas internas. Em muitos cenários sua lógica precisa pausar e aguardar algo que vai acontecer fora dela: a confirmação de um pagamento por webhook, a aprovação manual de um gerente, o callback de um sistema externo que pode demorar minutos, horas ou dias.

Para isso você usa `SkailTask.WaitForEvent` para pausar e `SkailTask.FireEvent` para, de outro lugar, liberar essa espera.

### WaitForEvent

Um `WaitForEvent` pausa a execução até que um evento com o mesmo nome e o mesmo instance id seja disparado. O nome identifica o *tipo* do evento (por exemplo, `"CONFIRMACAO_PAGAMENTO"`); o instance id identifica *qual* instância específica está sendo aguardada (por exemplo, o id do pedido).

```csharp
[SkailFunction]
public async SkailTask ProcessarPedido(Guid pedidoId)
{
    await RegistrarPedido(pedidoId);

    await SkailTask.WaitForEvent("CONFIRMACAO_PAGAMENTO", pedidoId.ToString());

    await LiberarEnvio(pedidoId);
}
```

Enquanto o evento não chega, sua aplicação não fica bloqueada esperando. O runtime da skail persiste o estado da execução, libera os recursos e retoma automaticamente o método assim que o evento correspondente for disparado — seja daqui a 5 segundos ou daqui a 3 dias.

#### Recebendo dados junto com o evento

Na maior parte dos casos o evento não apenas sinaliza que algo aconteceu, mas também traz dados. Use a versão genérica `WaitForEvent<T>` para receber um payload tipado:

```csharp
[SkailFunction]
public async SkailTask ProcessarPedido(Guid pedidoId)
{
    await RegistrarPedido(pedidoId);

    var confirmacao = await SkailTask.WaitForEvent<ConfirmacaoPagamento>(
        "CONFIRMACAO_PAGAMENTO",
        pedidoId.ToString()
    );

    if (confirmacao.Aprovado)
        await LiberarEnvio(pedidoId);
    else
        await CancelarPedido(pedidoId, confirmacao.MotivoRecusa);
}
```

### FireEvent

Do outro lado da história está quem dispara o evento. Pode ser outra função dentro do mesmo workload, uma função em outro serviço, ou um endpoint que recebe um webhook externo e traduz para um `FireEvent`.

```csharp
[SkailFunction]
public async SkailTask ConfirmarPagamento(Guid pedidoId, ConfirmacaoPagamento confirmacao)
{
    await RegistrarConfirmacao(pedidoId, confirmacao);

    await SkailTask.FireEvent("CONFIRMACAO_PAGAMENTO", pedidoId.ToString(), confirmacao);
}
```

O nome e o instance id precisam ser idênticos aos usados no `WaitForEvent` correspondente — é esse par que conecta um ao outro. Use `FireEvent` (sem tipo) quando o evento serve apenas como sinal e não carrega dados.

### Combinando com Delay para timeout

Um padrão comum é limitar por quanto tempo você está disposto a esperar pelo evento. Combine `WaitForEvent` com um `Delay` dentro de um `WhenAny`:

```csharp
[SkailFunction]
public async SkailTask ProcessarPedido(Guid pedidoId)
{
    await RegistrarPedido(pedidoId);

    var confirmacao = SkailTask.WaitForEvent<ConfirmacaoPagamento>(
        "CONFIRMACAO_PAGAMENTO",
        pedidoId.ToString()
    );
    var timeout = SkailTask.Delay(TimeSpan.FromHours(24));

    var resultado = await SkailTask.WhenAny(confirmacao, timeout);

    if (resultado == timeout)
    {
        await CancelarPorExpiracao(pedidoId);
        return;
    }

    await LiberarEnvio(pedidoId);
}
```

Se a confirmação não chegar em 24 horas, o pedido é cancelado automaticamente. Se chegar antes, o fluxo segue normalmente.

### Pausando uma função até um evento externo ocorrer

Em fluxos reais, nem toda continuação depende apenas do próprio código. Às vezes a função precisa esperar uma ação humana, um webhook, uma confirmação de pagamento ou a resposta de outro sistema.

Para isso, o skail usa o par:

* `SkailTask.WaitForEvent<T>(eventName, instanceId)`: pausa a função até o evento chegar.
* `SkailTask.FireEvent(eventName, instanceId, payload)`: dispara o evento que libera a espera.

O ponto importante é que `eventName` e `instanceId` precisam ser exatamente os mesmos dos dois lados. Esse par identifica qual execução deve acordar.

#### Exemplo 1 — Processo com aprovação manual e API externa

```csharp
// SkailFunction = função durável. Se cair no meio, retoma de onde parou.
[SkailFunction]
public async SkailTask ProcessarSolicitacao(SolicitacaoRequest request)
{
    // Etapa 1: operação no banco
    // SkailCommand = checkpoint. Se o banco der timeout, retry automático.
    await ExecutarValidacao(request);

    // Etapa 2: espera aprovação manual
    // WaitForEvent = hiberna a função. Zero custo enquanto espera.
    // Quando alguém aprova no frontend, faz um POST/fire-event e acorda.
    var aprovacao = await SkailTask.WaitForEvent<AprovacaoRequest>(
        "APROVACAO_SOLICITACAO",
        request.Id
    );

    if (!aprovacao.Aprovado) return;

    // Etapa 3: chama API externa
    // Se a API cair, retry automático com backoff.
    var resultado = await ChamarApiExterna(aprovacao);

    // Etapa 4: espera confirmação externa
    // Exemplo: webhook recebido por outro endpoint dispara um fire-event.
    var confirmacao = await SkailTask.WaitForEvent<ConfirmacaoExterna>(
        "CONFIRMACAO_EXTERNA",
        resultado.TransacaoId
    );

    await RegistrarConclusao(request.Id, confirmacao);
}
```

#### Node.js chamando a Skail

Iniciar o processo é um POST para o endpoint de trigger. O payload enviado para o trigger deve ser um array.

```typescript
const url = `${SKAIL_BASE_URL}/trigger/${WORKLOAD}/${VERSION}/ProcessarSolicitacao/${requestId}`;

await fetch(url, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    Authorization: `Bearer ${SKAIL_KEY}`,
    'skail-key': SKAIL_KEY,
    'Skail-namespace': SKAIL_NAMESPACE,
  },
  body: JSON.stringify([request]),
});

```

Para acordar uma função que está parada em WaitForEvent, dispare um fire-event com o mesmo nome de evento e o mesmo instanceId.

```typescript
// Exemplo: aprovação manual feita no frontend.
const url = `${SKAIL_BASE_URL}/api/v1/fire/APROVACAO_SOLICITACAO/${requestId}`;

await fetch(url, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    Authorization: `Bearer ${SKAIL_KEY}`,
    'skail-key': SKAIL_KEY,
    'Skail-namespace': SKAIL_NAMESPACE,
  },
  body: JSON.stringify({
    aprovado: true,
    observacao: 'ok',
  }),
});

```

O mesmo padrão vale para webhooks externos:

```typescript
// Exemplo: confirmação recebida da API externa.
const url = `${SKAIL_BASE_URL}/api/v1/fire/CONFIRMACAO_EXTERNA/${transacaoId}`;

await fetch(url, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    Authorization: `Bearer ${SKAIL_KEY}`,
    'skail-key': SKAIL_KEY,
    'Skail-namespace': SKAIL_NAMESPACE,
  },
  body: JSON.stringify(confirmacao),
});

```

### Observabilidade

No portal do skail, na seção Monitor, uma função aguardando em `WaitForEvent` aparece com o status *aguardando evento*, junto com o nome e o instance id esperados. Isso facilita diagnosticar situações em que o evento nunca chegou (nome divergente, instance id errado, webhook que nunca foi entregue) e entender quanto tempo cada execução passou esperando.

Cada `FireEvent` também aparece como um item próprio, o que permite correlacionar quem liberou qual espera.
