> 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/referencia/sdk-csharp/skailfunction.md).

# \[SkailFunction]

Marca um método como orquestrador durável.

O método vira um ponto de entrada de execução: o skail inicia, retoma e acompanha o fluxo a partir dele. Esta é a referência do atributo; o conceito está em [Modelo de programação](/construa/conceitos/functions-e-commands.md).

## Assinatura

{% tabs %}
{% tab title="C#" %}

```csharp
// Formas do atributo (use uma por método):
// [SkailFunction]
// [SkailFunction(retryCount: 3)]
// [SkailFunction(skailMethodName: "EmitirFaturaV2")]
// [SkailFunction(skailMethodName: "EmitirFaturaV2", retryCount: 5)]
[SkailFunction]
public async SkailTask NomeDoMetodo(/* argumentos */)   // ou SkailTask<T>
```

{% endtab %}

{% tab title="TypeScript" %}

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

export class Assinaturas {
  // Formas do decorator (use uma por método):
  @SkailFunction()
  async nomeDoMetodo(/* argumentos */): Promise<void> {}

  @SkailFunction({ retryCount: 3 })
  async comRetry(): Promise<void> {}

  // O uri é usado literalmente: os dois endereços abaixo ficam presos a faturamento:v1.0.0,
  // mesmo que o SKAIL_WORKLOAD mude de versão. Ver "Endereço (URI)" abaixo.
  @SkailFunction({ uri: "faturamento:v1.0.0/EmitirFaturaV2" })
  async emitirFaturaV2(): Promise<void> {}

  @SkailFunction({ uri: "faturamento:v1.0.0/EmitirFaturaV2Retry", retryCount: 5 })
  async emitirFaturaV2ComRetry(): Promise<number> {
    return 1;
  }
}
```

{% endtab %}
{% endtabs %}

| Parâmetro         | Tipo      | Default | Descrição                                                                                             |
| ----------------- | --------- | ------- | ----------------------------------------------------------------------------------------------------- |
| `skailMethodName` | `string?` | `null`  | Endereço explícito da function. Ver regras de URI abaixo.                                             |
| `retryCount`      | `uint`    | `15`    | Máximo de reentregas da execução quando a function lança exceção. Commands já concluídos não repetem. |

## Regras do método

| Regra                                 | Detalhe                                                                                                                                  | Quem cobra                                            |
| ------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------- |
| Método de instância                   | Nunca `static`. A classe é registrada no DI automaticamente                                                                              | Analyzer (SKAIL001)                                   |
| `async`                               | Sempre                                                                                                                                   | Analyzer (SKAIL002)                                   |
| Retorno `SkailTask` ou `SkailTask<T>` | Nunca `Task`/`Task<T>`                                                                                                                   | Analyzer (SKAIL001)                                   |
| `public`                              | Sempre `public`                                                                                                                          | Analyzer (SKAIL001)                                   |
| Argumentos e retorno serializáveis    | `System.Text.Json`: primitivos, `Guid`, `DateTime`, records, DTOs, coleções. Nunca `SkailTask`                                           | Runtime, ao registrar o passo                         |
| Corpo determinístico                  | Sem I/O, relógio, aleatoriedade, `Task.Delay`, `Task.WhenAll`. Ver [Determinismo e replay](/construa/conceitos/replay-e-determinismo.md) | Runtime, no replay (`SkailNonDeterministicException`) |

## Comportamento

O corpo é reexecutado a cada retomada (início, fim de delay, evento recebido, falha, restart). A cada `await`, o runtime devolve o resultado daquela vez se o passo já foi concluído, ou executa e registra o passo. Pode chamar:

* `[SkailCommand]`;
* outras `[SkailFunction]` (que viram orquestrações filhas com o próprio histórico);
* as primitivas `SkailTask.*`.

Uma function é iniciada pelo trigger ou chamada por outra function, nunca por um command.

Quando o corpo lança exceção (inclusive uma vinda de command que esgotou o próprio `retryCount`), a execução é reentregue até `retryCount` vezes; ao esgotar, fica como falha no Monitor e pode ser retomada manualmente. Ver [Falhas, retries e idempotência](/construa/conceitos/retries-e-idempotencia.md).

## Endereço (URI) e skailMethodName

Toda function tem um endereço no formato `nome:versao/metodo`, onde `nome:versao` é o workload (`SKAIL_WORKLOAD`). É esse endereço que o trigger usa (`/api/v1/trigger/{workload}/{versao}/{funcao}/{id}`) e ao qual as execuções em andamento continuam endereçadas.

Em C#, o endereço resulta do `skailMethodName` assim:

| `skailMethodName`                                                | Endereço resultante                       |
| ---------------------------------------------------------------- | ----------------------------------------- |
| omitido                                                          | `{workload atual}/{NomeDoMetodo}`         |
| `"EmitirFaturaV2"` (só nome)                                     | `{workload atual}/EmitirFaturaV2`         |
| `"faturamento:v2.0.0/EmitirFatura"` com o mesmo nome de workload | `{workload atual}/EmitirFatura`           |
| `"faturamento:v2.0.0/EmitirFatura"` com outro nome de workload   | literal `faturamento:v2.0.0/EmitirFatura` |

O uso principal é versionar: manter a function antiga com o nome antigo e publicar a nova com outro `skailMethodName`, enquanto execuções em andamento terminam. Para isso, use um nome novo (`"EmitirFaturaV2"`): o endereço passa a ser `{workload atual}/EmitirFaturaV2`, diferente do endereço da function antiga. Um `skailMethodName` no formato `nome:versao/metodo` com o mesmo nome do workload atual não versiona pela versão: ele resolve para `{workload atual}/metodo` e a versão escrita no atributo é ignorada. Ver [Versionamento](/construa/conceitos/versoes-com-execucoes-em-andamento.md). Prefira um nome só com letras e números.

Em TypeScript, a opção `uri` não segue a tabela acima: o valor é usado literalmente. `@SkailFunction({ uri: "faturamento:v1.0.0/EmitirFaturaV2" })` fica preso a `faturamento:v1.0.0`, mesmo depois que o workload passa para outra versão. Para versionar só o método em TypeScript, publique a function nova como um método de nome novo, sem `uri`; o endereço passa a ser `{workload atual}/{nomeDoMetodo}`.

## Exemplo

{% tabs %}
{% tab title="C#" %}

```csharp
using Skail.Platform.Runtime;
using Skail.Platform.Runtime.Threading;

public class Faturamento
{
    private readonly IGatewayPagamento _gateway;
    public Faturamento(IGatewayPagamento gateway) => _gateway = gateway;

    [SkailFunction(retryCount: 10)]
    public async SkailTask<bool> EmitirFatura(Guid faturaId, decimal valor)
    {
        var resultado = await CobrarCartao(faturaId, valor);
        if (resultado != ResultadoCobranca.Aprovado) return false;

        await SkailTask.Delay(TimeSpan.FromDays(1));
        await EmitirNota(faturaId);
        return true;
    }

    [SkailCommand]
    public async SkailTask<ResultadoCobranca> CobrarCartao(Guid faturaId, decimal valor)
        => await _gateway.Cobrar(faturaId, valor); // faturaId como chave de idempotência

    [SkailCommand]
    public async SkailTask EmitirNota(Guid faturaId) { /* ... */ }
}
```

{% endtab %}

{% tab title="TypeScript" %}

```typescript
import { Skail, SkailCommand, SkailFunction } from "@skail/runtime";
import type { Provider } from "@skail/runtime";
import { GatewayPagamento } from "./servicos.js";

type ResultadoCobranca = "Aprovado" | "Recusado";

interface IGatewayPagamento {
  cobrar(faturaId: string, valor: number): Promise<ResultadoCobranca>;
}

const UM_DIA_MS = 24 * 60 * 60 * 1000;

export class Faturamento {
  private readonly gateway: IGatewayPagamento;
  constructor(gateway: IGatewayPagamento) {
    this.gateway = gateway;
  }

  @SkailFunction({ retryCount: 10 })
  async emitirFatura(faturaId: string, valor: number): Promise<boolean> {
    const resultado = await this.cobrarCartao(faturaId, valor);
    if (resultado !== "Aprovado") return false;

    await Skail.delay(UM_DIA_MS);
    await this.emitirNota(faturaId);
    return true;
  }

  @SkailCommand()
  async cobrarCartao(faturaId: string, valor: number): Promise<ResultadoCobranca> {
    return await this.gateway.cobrar(faturaId, valor); // faturaId como chave de idempotência
  }

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

export const providers: Provider[] = [
  {
    token: Faturamento,
    useFactory: (services) => new Faturamento(services.resolve(GatewayPagamento)),
  },
];
```

{% endtab %}
{% endtabs %}

## Observabilidade

Cada execução aparece no Monitor com TaskId, estado, linha do tempo dos passos, retentativas e erros; cada function abre um span de rastreamento sob o `traceparent` do trigger. Functions filhas aparecem correlacionadas à pai.

## Erros relacionados

| Erro                                    | Causa                                                                                                  |
| --------------------------------------- | ------------------------------------------------------------------------------------------------------ |
| SKAIL001 / SKAIL002 na compilação       | Assinatura fora das regras                                                                             |
| `SkailNonDeterministicException`        | Corpo não determinístico ou fluxo alterado com execuções em andamento                                  |
| Execução parada em Na fila, sem retomar | Endereço da execução não corresponde a nenhuma function publicada: `SKAIL_WORKLOAD` ou nome diferentes |
| "StateMachine not registered."          | Método não descoberto: assembly sem `[assembly: VisibleToSkailPlatform]`, método não `async`           |

## Veja também

[SkailCommand](/referencia/sdk-csharp/skailcommand.md), [SkailTask e SkailTask\<T>](/referencia/sdk-csharp/skailtask-e-skailtask-less-than-t-greater-than.md), [Regras do analyzer](/referencia/sdk-csharp/regras-do-analyzer.md), [POST /api/v1/trigger](/referencia/api-http/post-trigger.md).
