Cancellation¶
TeleFlow carries cancellation through the update pipeline. Handler methods can receive the current update token, and context-bound Telegram helpers use that token when you do not pass one explicitly.
Handler Tokens¶
[Command("start")]
public Task Start(MessageContext ctx, CancellationToken ct)
{
return ctx.Message.AnswerAsync("Ready.");
}
Keep the token in the handler signature even if a small handler does not use it yet. The handler is the boundary where application services, repositories, HTTP clients, queues, and other I/O should receive cancellation explicitly.
[Command("report")]
public async Task Report(MessageContext ctx, IReportService reports, CancellationToken ct)
{
var report = await reports.BuildAsync(ctx.Sender?.Id, ct);
await ctx.Message.AnswerAsync(report.Title);
}
Context-Bound Telegram Helpers¶
The helpers exposed by TeleFlow contexts are bound to the current update:
await ctx.Message.AnswerAsync("Saved.");
await ctx.Callback.AnswerAsync();
await ctx.Callback.EditTextAsync("Done.");
await ctx.Chat.ActionAsync(ChatAction.Typing);
If no token is passed, these helpers use the update cancellation token. A non-cancelable token such as CancellationToken.None is treated the same way in context-bound Telegram helpers. If you pass a cancelable token explicitly, that token wins.
ctx.Bot Calls¶
Generated client methods also accept cancellation tokens, but ctx.Bot is update-scoped inside handlers:
using TeleFlow.Telegram.Schema.Abstractions;
await ctx.Bot.SendMessageAsync(
chatId: IntegerString.From(ctx.TelegramChat.Id),
text: "Processing complete.");
The same generated method called on a root ITelegramClient from DI is not update-scoped. Outside a handler context, pass the token explicitly.
public sealed class BroadcastService(ITelegramClient bot)
{
public Task SendAsync(long chatId, string text, CancellationToken ct)
{
return bot.SendMessageAsync(
chatId: IntegerString.From(chatId),
text: text,
cancellationToken: ct);
}
}
Recommended Rule¶
Use this rule:
- keep
CancellationToken ctin async handlers; - pass
ctto your own I/O: database calls, HTTP calls, queues, storage, EF Core, and background work; - omit
ctforctx.Message,ctx.Callback,ctx.Chat, andctx.Botcalls inside handlers when you want the current update token; - pass an explicit token only when you intentionally want different cancellation semantics;
- do not hide cancellation in application services through ambient state or static accessors.
This keeps small bots readable without making production code depend on hidden cancellation behavior.