Skip to content

feat(telegram): use grammyjs/runner for concurrent update processing#366

Closed
mukhtharcm wants to merge 2 commits intoopenclaw:mainfrom
mukhtharcm:fix/telegram-parallel-handler
Closed

feat(telegram): use grammyjs/runner for concurrent update processing#366
mukhtharcm wants to merge 2 commits intoopenclaw:mainfrom
mukhtharcm:fix/telegram-parallel-handler

Conversation

@mukhtharcm
Copy link
Copy Markdown
Member

@mukhtharcm mukhtharcm commented Jan 7, 2026

Problem

Telegram message processing was completely sequential, blocking all messages while one was being handled. This made the maxConcurrent config setting ineffective for Telegram users.

Root Cause

grammY's default bot.start() uses sequential update processing:

// node_modules/grammy/out/bot.js
async handleUpdates(updates) {
    // handle updates sequentially (!)  <-- grammY's own comment!
    for (const update of updates) {
        await this.handleUpdate(update);  // Blocks until complete
    }
}

This meant:

  • While responding to one chat, ALL other Telegram messages queued
  • Ack reactions (👀) didn't appear until the queue cleared
  • Long-running tool calls blocked every other conversation
  • Multi-chat parallelism was completely broken

How Other Providers Handle This

Provider Implementation Concurrent?
Discord Promise.all(listeners.map(...)) ✅ Yes
WhatsApp void task.catch(...) (fire-and-forget) ✅ Yes
Telegram await handleUpdate() in for-loop ❌ No

Discord and WhatsApp already processed messages in parallel. Only Telegram was affected.

Visual Example

Before (sequential):

Msg A arrives → handler starts → [30 sec tool call] → handler ends
Msg B arrives → [BLOCKED 30 sec] → handler starts → ...
Msg C arrives → [BLOCKED 60 sec] → ...

After (concurrent with runner):

Msg A arrives → handler starts in parallel →
Msg B arrives → handler starts in parallel →
Msg C arrives → handler starts in parallel →
(all processing concurrently, limited by maxConcurrent)

Solution

Use @grammyjs/runner which is the official grammY plugin for concurrent update processing.

Changes

  1. Added @grammyjs/runner dependency
  2. Replaced bot.start() with run(bot) in src/telegram/monitor.ts
  3. Proper abort signal handling for graceful shutdown

Code Change

- await bot.start();
+ const runner = run(bot, {
+   runner: { fetch: { timeout: 30 } },
+ });
+ await runner.task();

Benefits

  • ✅ Ack reactions (👀) appear immediately
  • ✅ Multiple chats processed in parallel
  • maxConcurrent setting now works for Telegram
  • ✅ Long tool calls don't block other conversations
  • ✅ Consistent behavior across all providers

Testing

Tested on dev container with:

  • Rapid messages to DM and group simultaneously
  • Both processed concurrently without blocking
  • Verified parallel execution in logs

Related

This was discovered while investigating why ack reactions were delayed. The deeper issue was that the entire Telegram provider was single-threaded.

Previously, grammY's default bot.start() processed updates sequentially,
blocking all Telegram messages while one was being handled. This made
maxConcurrent settings ineffective for Telegram.

Now uses @grammyjs/runner which processes updates concurrently, matching
the behavior of Discord (Promise.all) and WhatsApp (fire-and-forget).

Benefits:
- Ack reactions (👀) appear immediately, not after queue clears
- Multiple chats can be processed in parallel
- maxConcurrent setting now works correctly for Telegram
- Long-running tool calls no longer block other conversations
@steipete steipete self-assigned this Jan 7, 2026
@mukhtharcm mukhtharcm force-pushed the fix/telegram-parallel-handler branch from 9ffa470 to 519812b Compare January 7, 2026 19:46
@steipete
Copy link
Copy Markdown
Contributor

steipete commented Jan 7, 2026

Landed via fast-forward on main. Added per-chat sequentialization + runner concurrency cap + tests + changelog, plus a small typebox schema mismatch fix to keep builds green. Commits: 47e4bf8ca, f6051eea0, e27db4083, 7f9de5aea.

@steipete steipete closed this Jan 8, 2026
dgarson added a commit to dgarson/clawdbot that referenced this pull request Feb 9, 2026
…ls, gateway wiring) (openclaw#366)

* Obsidian: add vault integration scaffolding

* Obsidian: update link index before filtering self-authored
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants