> 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/construir/sdk-.net/whenall-e-whenany.md).

# WhenAll e WhenAny

Composição de várias `SkailTask` dentro de uma function: `WhenAll` espera todas concluírem, `WhenAny` devolve a primeira que concluir. São as versões duráveis de `Task.WhenAll` e `Task.WhenAny`, que não podem ser usadas em functions.

## Assinaturas

```csharp
public static SkailTask WhenAll(params SkailTask[] tasks);
public static SkailTask<SkailTask> WhenAny(params SkailTask[] tasks);
```

| Método    | Devolve                                  | Conclui quando                                                           |
| --------- | ---------------------------------------- | ------------------------------------------------------------------------ |
| `WhenAll` | Nada (aguarde e depois leia cada tarefa) | Todas as tarefas concluíram. Se alguma lançou exceção, `WhenAll` propaga |
| `WhenAny` | A `SkailTask` que concluiu primeiro      | A primeira tarefa concluiu. As outras continuam em segundo plano         |

Só dentro de `[SkailFunction]`. Dentro de `[SkailCommand]`, use `Task.WhenAll` normalmente.

## WhenAll

As tarefas são criadas sem `await` e passadas juntas; cada uma grava o próprio passo. Depois do `WhenAll`, dar `await` em cada tarefa devolve o resultado gravado sem esperar de novo. Leia pela posição da tarefa que você criou, não pela ordem de término, que não é garantida nem reproduzível.

```csharp
[SkailFunction]
public async SkailTask EmitirDocumento(Guid documentoId, Guid emitenteId)
{
    var emitente  = ConsultarEmitente(emitenteId);      // SkailTask<Emitente>
    var documento = GerarDocumento(documentoId);        // SkailTask<Documento>

    await SkailTask.WhenAll(emitente, documento);

    var dados = await emitente;                          // gravado; não espera de novo
    var doc   = await documento;

    await EnviarWebhook(documentoId, dados, doc);
}
```

`emitenteId` chega como parâmetro. Gerar um `Guid.NewGuid()` dentro da function quebraria o replay; identificadores novos vêm de fora ou de um command.

Cada vez que uma das tarefas conclui, o runtime retoma a execução brevemente para registrar o resultado e, se ainda faltam respostas, hiberna de novo. No Monitor, todas as operações aparecem na linha do tempo da function.

Um `Delay` entre as tarefas impõe um tempo mínimo: `await SkailTask.WhenAll(ConsultarEmitente(emitenteId), GerarDocumento(documentoId), SkailTask.DelayMinutes(1));` só avança quando as duas concluíram e o minuto passou.

Quantidade variável: `var tarefas = ids.Select(EmitirNota).ToArray(); await SkailTask.WhenAll(tarefas);` e depois `await tarefas[i]` na ordem dos ids.

## WhenAny

Devolve a própria `SkailTask` vencedora; compare por referência para saber qual foi.

```csharp
var consulta = ConsultarProvedorPrimario(cpf);
var reserva  = ConsultarProvedorSecundario(cpf);

var primeira = await SkailTask.WhenAny(consulta, reserva);
var resultado = primeira == consulta ? await consulta : await reserva;
```

O uso mais comum é dar prazo a uma espera:

```csharp
var operacao = ProcessarPagamento(pedidoId);
var timeout  = SkailTask.DelaySeconds(30);

if (await SkailTask.WhenAny(operacao, timeout) == timeout)
{
    await NotificarFalhaDeTimeout(pedidoId);
    return;
}
await ConfirmarPedido(pedidoId);
```

As tarefas que não venceram continuam executando em segundo plano até concluir ou até a function terminar; nenhuma é cancelada, e as respostas que chegam depois são registradas mas não alteram o caminho já tomado. A mesma tarefa pode participar de vários `WhenAny` em sequência (uma espera com vários prazos).

Aviso real sobre a semântica de "primeira": com muitas execuções esperando e poucas instâncias, qual tarefa conclui primeiro depende da ordem em que o trabalho é processado, não só da latência das operações. Para usar `WhenAny` como corrida de latência, garanta instâncias suficientes da aplicação.

## Observabilidade

Cada tarefa composta aparece como item próprio na linha do tempo do Monitor, com a duração de cada uma; em `WhenAny`, o item vencedor e os que concluíram depois.

## Erros relacionados

| Erro                             | Causa                                                                                                                               |
| -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| `SkailNonDeterministicException` | `Task.WhenAll`/`Task.WhenAny` em function; ou leitura por ordem de término que muda o caminho                                       |
| Exceção sai do `WhenAll`         | Uma das tarefas lançou (command esgotou `retryCount`); trate com `try/catch` em volta do `WhenAll` ou dentro de cada function filha |
| Tarefas rodam em sequência       | `await` em cada chamada antes de compor                                                                                             |

## Veja também

[Como executar em paralelo e agregar resultados](/construir/escrever-fluxos/como-executar-em-paralelo-e-agregar-resultados.md), [Como esperar com timeout](/construir/escrever-fluxos/como-esperar-com-timeout.md), [Fan-out / Fan-in](/construir/padroes-e-antipadroes/fan-out-fan-in.md), [Delay](/construir/sdk-.net/delay.md).
