Skip to content

Commit 1bdf436

Browse files
committed
fix(telegram): expose spooled handler timeout config
1 parent 21b33bd commit 1bdf436

7 files changed

Lines changed: 47 additions & 4 deletions

File tree

docs/channels/telegram.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,7 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
297297
- Multi-account startup bounds concurrent Telegram `getMe` probes so large bot fleets do not fan out every account probe at once.
298298
- Long polling is guarded inside each gateway process so only one active poller can use a bot token at a time. If you still see `getUpdates` 409 conflicts, another OpenClaw gateway, script, or external poller is likely using the same token.
299299
- Long-polling watchdog restarts trigger after 120 seconds without completed `getUpdates` liveness by default. Increase `channels.telegram.pollingStallThresholdMs` only if your deployment still sees false polling-stall restarts during long-running work. The value is in milliseconds and is allowed from `30000` to `600000`; per-account overrides are supported.
300+
- Isolated polling fails a claimed spooled update after 25 minutes by default so a wedged turn cannot block later same-chat messages indefinitely. Set `channels.telegram.spooledUpdateHandlerTimeoutMs` to a lower value, from `30000` to `3600000`, if your deployment prefers faster recovery over allowing very long Telegram-triggered tasks.
300301
- Telegram Bot API has no read-receipt support (`sendReadReceipts` does not apply).
301302

302303
<Note>
@@ -865,6 +866,7 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
865866
- `channels.telegram.mediaGroupFlushMs` (default 500) controls how long Telegram albums/media groups are buffered before OpenClaw dispatches them as one inbound message. Increase it if album parts arrive late; decrease it to reduce album reply latency.
866867
- `channels.telegram.timeoutSeconds` overrides Telegram API client timeout (if unset, grammY default applies). Bot clients clamp configured values below the 60-second outbound text/typing request guard so grammY does not abort visible reply delivery before OpenClaw's transport guard and fallback can run. Long polling still uses a 45-second `getUpdates` request guard so idle polls are not abandoned indefinitely.
867868
- `channels.telegram.pollingStallThresholdMs` defaults to `120000`; tune between `30000` and `600000` only for false-positive polling-stall restarts.
869+
- `channels.telegram.spooledUpdateHandlerTimeoutMs` defaults to `1500000`; tune between `30000` and `3600000` to control how long one isolated-ingress Telegram update can keep a lane claimed before OpenClaw fails it and drains later updates.
868870
- group context history uses `channels.telegram.historyLimit` or `messages.groupChat.historyLimit` (default 50); `0` disables.
869871
- reply/quote/forward supplemental context is normalized into one selected conversation context window when the gateway has observed the parent messages; the observed-message cache is persisted beside the session store. Telegram only includes one shallow `reply_to_message` in updates, so chains older than the cache are limited to Telegram's current update payload.
870872
- Telegram allowlists primarily gate who can trigger the agent, not a full supplemental-context redaction boundary.
@@ -1009,6 +1011,7 @@ Per-account, per-group, and per-topic overrides are supported (same inheritance
10091011
- If logs include `Polling stall detected`, OpenClaw restarts polling and rebuilds the Telegram transport after 120 seconds without completed long-poll liveness by default.
10101012
- `openclaw channels status --probe` and `openclaw doctor` warn when a running polling account has not completed `getUpdates` after startup grace, when a running webhook account has not completed `setWebhook` after startup grace, or when the last successful polling transport activity is stale.
10111013
- Increase `channels.telegram.pollingStallThresholdMs` only when long-running `getUpdates` calls are healthy but your host still reports false polling-stall restarts. Persistent stalls usually point to proxy, DNS, IPv6, or TLS egress issues between the host and `api.telegram.org`.
1014+
- Decrease `channels.telegram.spooledUpdateHandlerTimeoutMs` when Telegram updates are entering the isolated ingress spool but one `.processing` file keeps the same DM/chat lane blocked longer than your operational turn budget.
10121015
- Telegram also honors process proxy env for Bot API transport, including `HTTP_PROXY`, `HTTPS_PROXY`, `ALL_PROXY`, and their lowercase variants. `NO_PROXY` / `no_proxy` can still bypass `api.telegram.org`.
10131016
- If the OpenClaw managed proxy is configured through `OPENCLAW_PROXY_URL` for a service environment and no standard proxy env is present, Telegram uses that URL for Bot API transport too.
10141017
- On VPS hosts with unstable direct egress/TLS, route Telegram API calls through `channels.telegram.proxy`:

extensions/telegram/src/config-schema.test.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,19 @@ describe("telegram custom commands schema", () => {
6666
}
6767
});
6868

69+
it("accepts spooledUpdateHandlerTimeoutMs overrides per account", () => {
70+
const res = TelegramConfigSchema.safeParse({
71+
spooledUpdateHandlerTimeoutMs: 300_000,
72+
accounts: { ops: { spooledUpdateHandlerTimeoutMs: 600_000 } },
73+
});
74+
75+
expect(res.success).toBe(true);
76+
if (res.success) {
77+
expect(res.data.spooledUpdateHandlerTimeoutMs).toBe(300_000);
78+
expect(res.data.accounts?.ops?.spooledUpdateHandlerTimeoutMs).toBe(600_000);
79+
}
80+
});
81+
6982
it("accepts mediaGroupFlushMs overrides per account", () => {
7083
const res = TelegramConfigSchema.safeParse({
7184
mediaGroupFlushMs: 750,
@@ -129,6 +142,17 @@ describe("telegram custom commands schema", () => {
129142
expectTelegramConfigIssue({ pollingStallThresholdMs: 600_001 }, "pollingStallThresholdMs");
130143
});
131144

145+
it("rejects spooledUpdateHandlerTimeoutMs outside the isolated ingress handler bounds", () => {
146+
expectTelegramConfigIssue(
147+
{ spooledUpdateHandlerTimeoutMs: 29_999 },
148+
"spooledUpdateHandlerTimeoutMs",
149+
);
150+
expectTelegramConfigIssue(
151+
{ spooledUpdateHandlerTimeoutMs: 3_600_001 },
152+
"spooledUpdateHandlerTimeoutMs",
153+
);
154+
});
155+
132156
it("accepts textChunkLimit", () => {
133157
const res = TelegramConfigSchema.safeParse({
134158
enabled: true,

extensions/telegram/src/config-ui-hints.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,10 @@ export const telegramChannelConfigUiHints = {
129129
label: "Telegram Polling Stall Threshold (ms)",
130130
help: "Milliseconds without completed Telegram getUpdates liveness before the polling watchdog restarts the polling runner. Default: 120000.",
131131
},
132+
spooledUpdateHandlerTimeoutMs: {
133+
label: "Telegram Spooled Update Handler Timeout (ms)",
134+
help: "Maximum milliseconds a claimed isolated-ingress spool update may keep a Telegram lane active before OpenClaw fails it and lets later updates drain. Default: 1500000.",
135+
},
132136
silentErrorReplies: {
133137
label: "Telegram Silent Error Replies",
134138
help: "When true, Telegram bot replies marked as errors are sent silently (no notification sound). Default: false.",

extensions/telegram/src/monitor.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,7 @@ export async function monitorTelegramProvider(opts: MonitorTelegramOpts = {}) {
303303
timeoutSeconds: account.config.timeoutSeconds,
304304
proxy: account.config.proxy,
305305
network: account.config.network,
306+
spooledUpdateHandlerTimeoutMs: account.config.spooledUpdateHandlerTimeoutMs,
306307
},
307308
});
308309
await pollingSession.runUntilAbort();

0 commit comments

Comments
 (0)