Sleep and wait for events in a workflow
A paused run costs nothing while it waits. The SDK tells Inngest what the run is waiting for and the call ends. Inngest calls the function again when the time comes or the event arrives, and the function continues after the step. The app can be restarted, scaled down or redeployed in between.
Sleep for a duration
Section titled “Sleep for a duration”await context.Step.RunAsync("send-welcome", ct => email.SendAsync(context.Event.Data.Email, "Welcome!", ct));
await context.Step.SleepAsync("wait-three-days", TimeSpan.FromDays(3));
await context.Step.RunAsync("send-check-in", ct => email.SendAsync(context.Event.Data.Email, "How is it going?", ct));Durations are sent to Inngest in whole seconds, rounded down; one under a second, other than zero, becomes one second. A single sleep can last up to a year, within your plan’s maximum run length; see Inngest’s limits and sleep pages.
Sleep until a time
Section titled “Sleep until a time”SleepUntilAsync takes a DateTimeOffset. The SDK sends it to Inngest in UTC, so the offset you use does not
matter:
var reminder = await context.Step.RunAsync("load-reminder", ct => reminders.GetAsync(context.Event.Data.GetProperty("reminderId").GetString()!, ct));
await context.Step.SleepUntilAsync("wait-until-due", reminder.DueAt);
await context.Step.RunAsync("notify", ct => reminders.NotifyAsync(reminder.Id, ct));The time comes from a step, which keeps it the same on every call. A time computed outside a step, such as
DateTimeOffset.UtcNow.AddHours(1), would be different on each call and the step would move.
To delay the start of a whole function rather than part of it, send the triggering event with a future
Timestamp. See Sending events.
Wait for an event
Section titled “Wait for an event”WaitForEventAsync pauses until a matching event arrives, or until the timeout passes. It returns the event, or
null on timeout:
var user = context.Event.Data;
var activated = await context.Step.WaitForEventAsync<UserActivated>("wait-for-activation", TimeSpan.FromDays(3), match: "data.userId");
if (activated is null){ await context.Step.RunAsync("send-reminder", ct => email.SendAsync(user.Email, "Your account is waiting", ct));}UserActivated is a typed event, so the wait takes the
event’s name from the type and reads its data into it. For an event without a record of its own, name it in
WaitForEventOptions; the type argument is then only the data type, and leaving it out gives a JsonElement:
var reply = await context.Step.WaitForEventAsync("wait-for-reply", new WaitForEventOptions("support/ticket.replied", TimeSpan.FromDays(3)) { Match = "data.userId" });The timeout is required, so a run can never wait forever.
Matching the right event
Section titled “Matching the right event”Without a condition, any user/activated event resumes the wait, whoever it is for. Two options narrow it down:
Matchnames a property path that must be equal in the triggering event and the awaited one."data.userId"becomes the expressionevent.data.userId == async.data.userId.Ifis a full expression.eventis the event that triggered the run andasyncis the candidate event:
new WaitForEventOptions("billing/invoice.paid", TimeSpan.FromDays(14)){ If = "async.data.invoiceId == event.data.invoiceId && async.data.amount >= event.data.amount",}When both are set, both apply: the SDK joins them with &&. The typed form takes them as the match and @if
arguments.
Only events after the wait starts
Section titled “Only events after the wait starts”A wait sees events that arrive after it starts, not earlier ones. If the event can come before the function reaches the wait, for example because users often activate their account within seconds of signing up, wait as early in the function as you can, or check in a step whether it already happened before you wait. The Inngest docs on waitForEvent cover the details.
Waiting does not hold capacity
Section titled “Waiting does not hold capacity”A sleeping or waiting run does not use a concurrency slot, a thread or a connection. Thousands of runs can wait at once. If a waiting run should stop instead, for example when the user deletes their account, cancel it with an event: see cancellation.
SleepAsyncresumes after three days
WaitForEventAsyncthe event arrives: returns it
WaitForEventAsyncno event in 3 days: returns null
- a step runs
- paused: nothing runs in the app
- the awaited event
What Inngest stores
Section titled “What Inngest stores”A finished sleep is memoized as null, and a wait as the matching event or null. Replays return those values,
so code after a wait sees the same event on every call.
Related examples
Section titled “Related examples”User onboarding waits for an activation event, and scheduled reminders sleep until a due date.
inngest-dotnet is a community Inngest SDK for .NET. It is not affiliated with or endorsed by Inngest Inc.