You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过JavaScript更新Shiny UI实现长任务下WebSocket连接保活

Shiny云部署长任务连接超时解决方案

失效原因说明

你之前尝试的两种方案失效的原因分别是:

  • 服务端定时刷新方案:R为单线程运行,长计算任务执行期间会独占线程资源,无法响应invalidateLater的定时回调,直到任务结束才会处理后续逻辑,无法实现定期保活。
  • 原始JS方案:仅在控制台打印日志,既没有将时间值写入textOutput对应的DOM元素,也没有触发和Shiny服务端的WebSocket通信,无法实现页面更新和连接保活。

可直接使用的实现方案

1. UI代码调整

直接在你的现有UI中加入保活逻辑即可,不需要修改原有业务代码:

ui <- fluidPage(
  # 此处保留你原有的所有UI代码
  "Am I losing connection?",
  # 时间显示组件,可通过style设置为隐藏不影响页面展示
  textOutput("time_display", style = "position: absolute; top: -100px;"),
  # 注入保活JS代码
  tags$script(HTML("
    // 等待Shiny连接建立完成后再执行逻辑
    $(document).on('shiny:connected', function() {
      function keepAlive() {
        // 生成格式化时间字符串
        const now = new Date();
        const hr = String(now.getHours()).padStart(2, '0');
        const mn = String(now.getMinutes()).padStart(2, '0');
        const ss = String(now.getSeconds()).padStart(2, '0');
        const timeStr = `${hr}:${mn}:${ss}`;
        
        // 更新time_display组件的显示内容
        document.getElementById('time_display').textContent = timeStr;
        // 向Shiny服务端发送轻量事件,触发WebSocket通信,避免代理超时
        Shiny.setInputValue('keep_alive_ping', timeStr, {priority: 'event'});
      }
      // 每5秒执行一次保活逻辑
      setInterval(keepAlive, 5000);
    });
  "))
)

2. 服务端代码调整

服务端不需要额外添加任何处理逻辑,你原有长任务的代码完全不需要改动。keep_alive_ping输入事件仅用于触发WebSocket流量传输,不需要在服务端做监听和响应,云平台的反向代理/负载均衡只要检测到连接有数据传输,就不会判定为空闲断开。

注意事项

  • 如果你的云平台空闲超时阈值较短,可以将setInterval的5000(即5秒)调整为更小的数值,只要小于平台的空闲超时时间即可,常规云平台的WebSocket空闲超时多在30秒到10分钟区间,5秒间隔完全可以覆盖绝大多数场景。
  • 该逻辑不会占用过多服务端资源,传输的仅为长度极短的时间字符串,不会影响长任务的正常运行。

内容的提问来源于stack exchange,提问作者shpartan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.19 13:06:07