Skip to content

Function options builder

Everything Inngest controls about a function, from its triggers to flow control, goes in FunctionOptions, which the function class can also carry as attributes. When Inngest syncs the app, the SDK turns those options into JSON. Pick a preset or change the options, and the output shows the C# in both forms and that JSON. Like the other pages, it shows attributes first unless you picked Code first in one of their tabs.

Start from a preset

At most one run per account at a time, enterprise accounts first, cancelled when the account goes away.

Function
Triggers
Triggers in the Inngest docs
Concurrency in the Inngest docs
Throttle in the Inngest docs
Rate limit in the Inngest docs
Debounce in the Inngest docs
Batch events in the Inngest docs
Priority in the Inngest docs
Idempotency in the Inngest docs
Singleton in the Inngest docs
Timeout
Cancel on events in the Inngest docs
Timeouts in the Inngest docs

Valid. The SDK accepts these options and sends the JSON below when Inngest syncs the app.

Attributes

[InngestFunction("sync-account", Name = "Sync account", Retries = 5)]
[EventTrigger("account/updated")]
[Concurrency(20)]
[Concurrency(1, Key = "event.data.accountId")]
[Priority("event.data.plan == 'enterprise' ? 120 : 0")]
[CancelOn("account/deleted", Match = "data.accountId", Timeout = "1d")]
public sealed class SyncAccount : InngestFunction<JsonElement>
{
    // ...
}

builder.Services
    .AddInngest(options => options.AppId = "shop")
    .AddFunction<SyncAccount>();

Middleware and checkpointing have no attributes. Pass them to AddFunction in a callback, options => options with { ... }, which starts from the attributes.

Code first

var functionOptions = new FunctionOptions
{
    Id = "sync-account",
    Name = "Sync account",
    Triggers = [Trigger.Event("account/updated")],
    Retries = 5,
    Concurrency =
    [
        new ConcurrencyLimit(20),
        new ConcurrencyLimit(1) { Key = "event.data.accountId" },
    ],
    Priority = new Priority("event.data.plan == 'enterprise' ? 120 : 0"),
    CancelOn = [new CancelOn("account/deleted") { Match = "data.accountId", Timeout = TimeSpan.FromDays(1) }],
};

builder.Services
    .AddInngest(options => options.AppId = "shop")
    .AddFunction<SyncAccount>(functionOptions);

Registration JSON

{
  "url": "https://shop.example.com/api/inngest",
  "deployType": "ping",
  "appName": "shop",
  "sdk": "dotnet:v1.0.1-preview",
  "v": "0.1",
  "framework": "aspnetcore",
  "capabilities": {
    "trust_probe": "v1"
  },
  "functions": [
    {
      "id": "shop-sync-account",
      "name": "Sync account",
      "triggers": [
        {
          "event": "account/updated"
        }
      ],
      "steps": {
        "step": {
          "id": "step",
          "name": "step",
          "runtime": {
            "type": "http",
            "url": "https://shop.example.com/api/inngest?fnId=shop-sync-account&stepId=step"
          },
          "retries": {
            "attempts": 5
          }
        }
      },
      "concurrency": [
        {
          "limit": 20,
          "scope": "fn"
        },
        {
          "limit": 1,
          "key": "event.data.accountId",
          "scope": "fn"
        }
      ],
      "priority": {
        "run": "event.data.plan == 'enterprise' ? 120 : 0"
      },
      "cancel": [
        {
          "event": "account/deleted",
          "timeout": "1d",
          "if": "event.data.accountId == async.data.accountId"
        }
      ]
    }
  ]
}

The builder writes the JSON the same way the SDK’s RegistrationWriter does: the same properties in the same order, with durations as Inngest time strings (90 minutes becomes "1h30m") and options that are not set left out, so Inngest applies its defaults. A few details worth knowing:

  • A function’s id on the wire is <app id>-<function id>.
  • retries.attempts holds the number of retries, not attempts. Leave Retries empty to get Inngest’s default of 4 retries.
  • Match on a cancellation becomes the expression event.<path> == async.<path>.
  • A cron trigger with a time zone is sent with a TZ= prefix.
  • A class that implements IFailureHandler registers a second function, <id>-failure, triggered by inngest/function.failed.

The checks are the ones FunctionOptionsValidator makes when the app starts, and the SDK, like the builder, reports all the problems at once.

As attributes, the options sit on the function class, and AddFunction<TFunction>() reads them into FunctionOptions when the app starts, so both forms sync to the same JSON and go through the same checks. Each attribute sets one member:

Attribute Sets
[InngestFunction("id", Name, Retries, Idempotency)] Id, Name, Retries, Idempotency
[EventTrigger("name", If)], [EventTrigger<T>(If)] an EventTrigger in Triggers
[CronTrigger("schedule", Timezone, Jitter)] a CronTrigger in Triggers
[Concurrency(limit, Key, Scope)] a ConcurrencyLimit in Concurrency
[Throttle(limit, "period", Burst, Key)] Throttle
[RateLimit(limit, "period", Key)] RateLimit
[Debounce("period", Key, Timeout)] Debounce
[BatchEvents(maxSize, "timeout", Key, If)] BatchEvents
[Priority("run")] Priority
[Singleton(mode, Key)] Singleton
[CancelOn("name", If, Match, Timeout)], [CancelOn<T>(If, Match, Timeout)] a CancelOn in CancelOn
[Timeouts(Start, Finish)] Timeouts

The trigger, concurrency and cancellation attributes can be repeated. Durations are time strings such as "30s", "5m" or "1h30m". Middleware and Checkpointing have no attributes; set them with AddFunction<TFunction>(options => options with { ... }), which starts from the attributes. Options passed as AddFunction<TFunction>(new FunctionOptions { ... }) replace the attributes. An attribute of your own derives from FunctionOptionsAttribute, as all of these but [InngestFunction] do; Functions and triggers shows how.

The site’s build checks this page against the SDK: the snippet check compiles both forms of every preset, registers each in a real app and compares the JSON the SDK sends with the JSON shown here.

Flow control explains each option, and Functions and triggers covers ids, names and triggers.

inngest-dotnet is a community Inngest SDK for .NET. It is not affiliated with or endorsed by Inngest Inc.