fix(telegram): add socket timeout and extract tgApi into shared module#1399
fix(telegram): add socket timeout and extract tgApi into shared module#1399tommylin-signalpro wants to merge 5 commits intoNVIDIA:mainfrom
Conversation
Move the Telegram API client from an inline function in telegram-bridge.js into bin/lib/telegram-api.js. The new module accepts the bot token as a parameter instead of reading it from module-level state, and includes a 60s socket timeout with req.destroy() to prevent the poll loop from hanging on dead TCP connections. telegram-bridge.js now imports and wraps the shared function. Tests in test/telegram-api.test.js import the same production module and verify timeout, recovery, and error handling against local TLS servers. Refs: NVIDIA#1398 Signed-off-by: Tommy Lin <tommylin@signalpro.com.tw>
📝 WalkthroughWalkthroughAdds a shared Telegram Bot API client module ( Changes
Sequence Diagram(s)mermaid Bridge->>API: tgApiRaw(TOKEN, method, body, opts) Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@bin/lib/telegram-api.js`:
- Around line 47-57: The response handler for the HTTPS request only listens for
"data" and "end" which lets mid-stream errors or aborts hang the promise; update
the callback that receives the response (the res in the https.request callback)
to also attach res.on("error", ...) and res.on("aborted", ...) handlers that
immediately reject or resolve with an error object (consistent with the existing
resolve({ ok: false, error: ... })) so the outer Promise doesn't hang; apply the
same change to the other response handler instance referenced near line 61 to
ensure both places handle res errors/aborts.
In `@test/telegram-api.test.js`:
- Around line 156-160: The test "handles connection refused (server down)" races
because tempServer.close() is not awaited; change the close call to be awaited
by wrapping it in a Promise (e.g., await new Promise((resolve, reject) =>
tempServer.close(err => err ? reject(err) : resolve()))) so the server listener
is fully closed before issuing the API request; update the tempServer.close()
call in that test to use this awaited pattern referencing tempServer and the
test name to locate the change.
- Around line 69-75: The afterEach teardown is not awaiting server shutdowns so
handles linger; make afterEach async and await each server's close completion by
wrapping s.close in a Promise (or using a provided closeAsync) and resolving in
the close callback, ensuring s.closeAllConnections() is called first where
present; then await Promise.all over servers.map(...) (or sequential awaits) to
guarantee all s.close() completions before the test exits, and only then clear
the servers array.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 68bc192b-2545-4825-b290-7f896305a859
📒 Files selected for processing (3)
bin/lib/telegram-api.jsscripts/telegram-bridge.jstest/telegram-api.test.js
Address CodeRabbit review feedback on NVIDIA#1399: - Add res.on("error") and res.on("aborted") handlers with a settle guard to prevent promise hangs on mid-stream socket errors. - Make afterEach async and await server.close() to prevent lingering handles and port conflicts between tests. - Await tempServer.close() in the connection-refused test to eliminate a race condition. - Update mid-response test to assert rejection instead of accepting any outcome, now that aborted/error handlers are in place. Signed-off-by: Tommy Lin <tommylin@signalpro.com.tw>
There was a problem hiding this comment.
🧹 Nitpick comments (1)
bin/lib/telegram-api.js (1)
55-56: Make response decoding UTF-8 safe before JSON parse.Line 56 appends raw chunks directly to a string. If multibyte UTF-8 characters are split across chunks, content can be corrupted. Set encoding on
res(or accumulate Buffers andBuffer.concat) before parsing.Proposed patch
const req = https.request(reqOpts, (res) => { let buf = ""; + res.setEncoding("utf8"); res.on("data", (c) => (buf += c)); res.on("aborted", () => settle(reject, new Error(`Telegram API ${method} response aborted`))); res.on("error", (err) => settle(reject, err));🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@bin/lib/telegram-api.js` around lines 55 - 56, The response handling currently appends raw chunks to a string via res.on("data", ...) which can corrupt multibyte UTF-8 characters; update the handler in telegram-api.js around the res callbacks to decode safely by either calling res.setEncoding('utf8') before attaching data listeners or by accumulating Buffer objects (push each chunk in res.on("data", chunk) into an array, then Buffer.concat on 'end' and toString('utf8')) before JSON.parse; ensure the variable currently named buf and the res.on("end", ...) JSON.parse logic use the properly decoded string or buffer-to-string result.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@bin/lib/telegram-api.js`:
- Around line 55-56: The response handling currently appends raw chunks to a
string via res.on("data", ...) which can corrupt multibyte UTF-8 characters;
update the handler in telegram-api.js around the res callbacks to decode safely
by either calling res.setEncoding('utf8') before attaching data listeners or by
accumulating Buffer objects (push each chunk in res.on("data", chunk) into an
array, then Buffer.concat on 'end' and toString('utf8')) before JSON.parse;
ensure the variable currently named buf and the res.on("end", ...) JSON.parse
logic use the properly decoded string or buffer-to-string result.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: b85a7a1b-9e58-4577-ac97-7aae7be784f4
📒 Files selected for processing (2)
bin/lib/telegram-api.jstest/telegram-api.test.js
🚧 Files skipped from review as they are similar to previous changes (1)
- test/telegram-api.test.js
Add res.setEncoding("utf8") before attaching the data listener to
prevent multibyte UTF-8 characters from being corrupted when split
across chunks.
Signed-off-by: Tommy Lin <tommylin@signalpro.com.tw>
|
✨ Thanks for submitting this pull request, which proposes a way to fix a reliability issue in the Telegram bridge by adding socket timeouts. |
Problem
tgApi()inscripts/telegram-bridge.jshas no client-side socket timeout. When the TCP connection silently dies (e.g. NAT timeout, ISP routing change, network blip during the 30-second long-poll window), the HTTPS request hangs forever and the poll loop never recovers — the bot stops responding until the process is restarted.Root cause:
https.request()is called without atimeoutoption, and there is notimeoutevent handler. A dead TCP connection (no RST/FIN received) causes the request to wait indefinitely.Solution
Bug fix — add a 60s socket timeout with
req.destroy()on the timeout event. Longer than Telegram's 30s server-side long-poll, so normal responses are unaffected. The existingpoll()catch block already continues to the next iteration, so the loop self-heals.Extract shared module — move
tgApifrom an inline closure intelegram-bridge.jsintobin/lib/telegram-api.js. Token is now a parameter instead of captured from module scope. This lets tests import the real production function instead of duplicating it.Changes
bin/lib/telegram-api.jstgApi(token, method, body, opts)with timeout + opts for test overridesscripts/telegram-bridge.jstgApiwith one-line wrapper calling shared moduletest/telegram-api.test.jstgApi, verified against local TLS serversTest plan
Signed-off-by: Tommy Lin tommylin@signalpro.com.tw
Summary by CodeRabbit
Refactor
Tests