Skip to content

fix: speed up offline notification on disconnect (PMS #261905) - #783

Closed
Johnson-zs wants to merge 1 commit into
release/v20from
agent/pms-bug-bot/a5a1dfb7
Closed

Johnson-zs wants to merge 1 commit into
release/v20from
agent/pms-bug-bot/a5a1dfb7

Conversation

@Johnson-zs

@Johnson-zs Johnson-zs commented Aug 23, 2026 •

Copy link
Copy Markdown

Root Cause Analysis

Offline notification on network disconnect had ~6s total delay: Ping detection required 3 consecutive failures (~3s at 1s interval) before declaring offline (sendrpcservice.cpp:128), plus a fixed 3s cache timer in preprocessOfflineStatus (sendipcservice.cpp:314). The core defect was that preprocessOfflineStatus called connect(&_cacheTimer, ...) on every invocation without ever disconnecting (sendipcservice.cpp:315), causing Qt signal-slot connections to accumulate linearly — each timer timeout triggered multiple duplicate lambda executions. Additionally, sendToRemote (transferjob.cpp:748) held _send_mutex while blocking on a synchronous RPC whose recv timeout was hardcoded at 3000ms (tcpconnection.h:107), and setTimeout in rpcchannel.cpp:89 only set the connect timeout (m_max_timeout) without propagating to the actual recv/send timeout (m_trans_timeout).

Fix Approach

Five targeted changes: (1) moved the connect(&_cacheTimer, ...) from preprocessOfflineStatus to initConnect() for one-time setup, eliminating connection accumulation — the lambda capture changed from [this, appName] to [this] since the body iterates all keys; (2) reduced cache timer interval from 3000ms to 500ms; (3) lowered ping failure threshold from > 2 (3 failures) to > 1 (2 failures); (4) added setTransTimeout() to TcpConnection and modified TcpClient::setTimeout to propagate the timeout to m_trans_timeout via the connection; (5) added an early if (_offlined) return false; check at the start of sendToRemote to skip the blocking RPC when offline is already known.

Change Safety Assessment

Code Safety

  • Risk Level: Medium
  • The preprocessOfflineStatus connect accumulation was introduced in commit fcf512fa ("Fix remote offline unstable") as an implementation oversight, not intentional design — moving to initConnect() does not revert the original fix intent.
  • Commit 0c85b579 ("no prompt when networks disconnected", PMS 228107) modified curstatus at line 309 — our fix does not touch this line, no regression risk.
  • zrpc changes (tcpconnection.h, tcpclient.h) are additive: a new public method setTransTimeout() and a null-guarded propagation in the existing setTimeout setter — no signature changes, no existing caller affected.

Business Impact Scope

  • File transfer offline notification: Users will see offline notification ~2.5s after disconnect (down from ~6s), improving responsiveness of the "投送端提示" feature.
  • File transfer path: When offline is already detected, sendToRemote exits immediately instead of blocking up to 3s on a sync RPC, preventing UI freezes.
  • zrpc library timeout: The recv/send timeout is now configurable via the existing setTimeout API, benefiting all RPC callers that set a controller timeout.

Verification Suggestion

  1. Test file transfer with silent network disconnect (no FIN/RST) — verify offline notification arrives within ~3s.
  2. Test repeated offline/online cycles — verify no duplicate notifications or connection accumulation over many cycles.
  3. Verify normal file transfer (network intact) is unaffected — no false offline notifications.

根因分析

断网时离线通知全链路延迟约 6 秒:Ping 检测需连续失败 3 次(1 秒间隔,约 3 秒)才判离线(sendrpcservice.cpp:128),加上 preprocessOfflineStatus 固定 3 秒缓存定时器(sendipcservice.cpp:314)。核心缺陷在于 preprocessOfflineStatus 每次调用都执行 connect(&_cacheTimer, ...) 但从不 disconnect(sendipcservice.cpp:315),导致 Qt 信号槽连接数随调用线性累积——每次定时器超时触发多个重复 lambda 执行。此外,sendToRemote(transferjob.cpp:748)持 _send_mutex 阻塞在同步 RPC,recv 超时硬编码 3000ms(tcpconnection.h:107),而 rpcchannel.cpp:89 的 setTimeout 只设连接超时 m_max_timeout,未联动 recv/send 实际使用的 m_trans_timeout。

修复方案

五处针对性改动:(1) 将 connect(&_cacheTimer, ...) 从 preprocessOfflineStatus 移至 initConnect() 一次性建立,消除连接累积——lambda 捕获从 [this, appName] 改为 [this](函数体遍历所有 key,不需要 appName);(2) 缓存定时器间隔从 3000ms 降至 500ms;(3) Ping 失败阈值从 > 2(3 次)降至 > 1(2 次);(4) 为 TcpConnection 新增 setTransTimeout() 方法,修改 TcpClient::setTimeout 将超时传播至 m_trans_timeout;(5) 在 sendToRemote 入口增加 if (_offlined) return false; 早退检查,已知离线时跳过阻塞式 RPC。

改动安全评估

代码安全评估

  • 风险等级: 中风险
  • preprocessOfflineStatus 的 connect 累积问题由 commit fcf512fa("Fix remote offline unstable")引入,属实现疏漏而非设计意图——移至 initConnect() 不改变原修复目标。
  • commit 0c85b579("no prompt when networks disconnected",PMS 228107)修改了第 309 行 curstatus——本修复不涉及该行,无回归风险。
  • zrpc 改动(tcpconnection.h、tcpclient.h)均为新增:一个公有方法 setTransTimeout() 和 setTimeout 中带空指针保护的传播——无签名变更,不影响现有调用者。

业务影响范围

  • 文件投送离线通知:断网后用户约 2.5 秒收到离线通知(原约 6 秒),提升"投送端提示"功能响应速度。
  • 文件投送传输路径:已知离线时 sendToRemote 立即退出,不再阻塞最多 3 秒在同步 RPC 上,避免 UI 卡死。
  • zrpc 库超时:recv/send 超时现可通过现有 setTimeout API 配置,惠及所有设置 controller 超时的 RPC 调用方。

验证建议

  1. 测试静默断网场景下文件投送(无 FIN/RST)——验证离线通知在 ~3 秒内到达。
  2. 测试反复断网/恢复循环——验证多轮循环后无重复通知或连接累积。
  3. 验证正常文件投送(网络正常)不受影响——无误报告离线通知。

PMS: BUG-261905

Summary by Sourcery

Improve disconnect handling so remote offline notifications arrive faster and known-offline transfers return promptly.

Bug Fixes:

  • Speed up offline notifications after network disconnects by reducing detection and status-cache delays.
  • Prevent file transfer operations from blocking on synchronous RPCs once the remote is known to be offline.
  • Eliminate duplicate offline-status processing caused by accumulating timer connections.

Enhancements:

  • Make configured RPC timeouts apply to connection transmission operations as well as connection establishment.

1. Root cause: Offline notification had ~6s delay (3s ping threshold
   + 3s cache timer). preprocessOfflineStatus called connect() on
   every invocation without disconnect, leaking Qt connections. Also
   sendToRemote blocked on sync RPC during known offline state.
2. Fix: Move cacheTimer connect to initConnect for one-time setup,
   reduce cache interval to 500ms, lower ping threshold from 3 to 2,
   propagate setTimeout to m_trans_timeout, add early offline check
   in sendToRemote
3. Impact: Offline notification reaches frontend in ~2.5s instead of
   ~6s. No connection accumulation. Transfer exits immediately when
   offline known. zrpc timeout now configurable via setTimeout API

Log: Speed up offline notification when network disconnects

Influence:
1. Test file transfer with network disconnect (silent, no FIN/RST)
2. Test offline notification timing and repeated offline/online cycles
3. Verify normal file transfer unaffected

fix: 加快断网时离线通知速度

1. 根因:离线通知全链路延迟约 6 秒(Ping 检测 3 秒 + 缓存定时器 3 秒)。
   preprocessOfflineStatus 每次调用执行 connect 但从不 disconnect,连接
   数线性累积。sendToRemote 在已知离线时仍阻塞在同步 RPC。
2. 方案:将 cacheTimer 连接移至 initConnect 一次性建立,缓存间隔降至
   500ms,Ping 失败阈值从 3 降为 2,setTimeout 同时设置 m_trans_timeout,
   sendToRemote 入口增加离线早退检查。
3. 影响:离线通知约 2.5 秒到达前端(原约 6 秒)。无连接累积。传输路径
   在已知离线时立即退出。zrpc 超时可通过现有 setTimeout API 配置。

Log: 加快网络断开时离线通知速度

Influence:
1. 测试断网场景下文件投送(静默断开,无 FIN/RST)
2. 测试离线通知时延及反复断网/恢复循环
3. 验证正常文件投送流程不受影响

PMS: BUG-261905

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @Johnson-zs, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

@deepin-ci-robot

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: Johnson-zs

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@sourcery-ai

sourcery-ai Bot commented Aug 23, 2026

Copy link
Copy Markdown

Reviewer's Guide

Speeds up and de-duplicates offline notifications and avoids unnecessary blocking RPC calls by fixing the offline status cache timer wiring, tuning ping and timer thresholds, and propagating RPC timeouts from the client to the underlying TCP connection.

Sequence diagram for faster offline notification

sequenceDiagram
    participant Ping as SendRpcWork
    participant IPC as SendIpcService
    participant Timer as cacheTimer
    participant Frontend as Frontend

    Ping->>Ping: handlePing
    alt 2 consecutive ping failures
        Ping->>IPC: preprocessOfflineStatus
        IPC->>Timer: startOfflineTimer
        Timer-->>IPC: timeout after 500ms
        IPC->>Frontend: Frontend.notifySendStatus
    end
Loading

Flow diagram for skipping offline transfer RPC

flowchart TD
    Start[sendToRemote] --> Device{_device_not_enough?}
    Device -->|yes| Reject[return false]
    Device -->|no| Offline{_offlined?}
    Offline -->|yes| Reject
    Offline -->|no| RPC[Synchronous remote transfer RPC]
Loading

File-Level Changes

Change Details Files
Fix offline-status cache timer wiring and tuning to avoid signal accumulation and reduce notification delay.
  • Move QTimer timeout connection from preprocessOfflineStatus into initConnect so it is set up once instead of per call.
  • Simplify the lambda capture for the cache timer from [this, appName] to [this] and keep iterating over all cached app names.
  • Lower the cache timer interval from 3000ms to 500ms to send offline notifications sooner.
src/plugins/daemon/core/service/ipc/sendipcservice.cpp
Avoid unnecessary blocking RPC when offline is already detected.
  • Add an early _offlined check at the start of sendToRemote to return false without taking the blocking RPC path when offline is known.
src/plugins/daemon/core/service/job/transferjob.cpp
Make offline detection more responsive by reducing ping failure threshold.
  • Change ping failure threshold from count > 2 to count > 1 before declaring the remote offline and emitting the offline notification.
src/plugins/daemon/core/service/rpc/sendrpcservice.cpp
Propagate controller timeout settings to the underlying TCP connection’s transport timeout.
  • Add setTransTimeout(int) to TcpConnection to allow configuring m_trans_timeout.
  • Update TcpClient::setTimeout to call setTransTimeout on the active TcpConnection when present, keeping existing m_max_timeout behavior.
3rdparty/zrpc/src/net/tcpconnection.h
3rdparty/zrpc/src/net/tcpclient.h

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@Johnson-zs Johnson-zs closed this Aug 24, 2026
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.

3 participants