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

如何实现Sidekiq异步任务完成后自动刷新页面优化用户体验?

无需手动刷新的Sidekiq任务结果展示方案

针对你遇到的Sidekiq异步任务执行后需手动刷新页面才能看到数据的问题,以下是几种可行的实现方案:

方案一:前端轮询检查任务状态

通过前端定时请求后端接口查询任务状态,任务完成后自动刷新页面。

实现步骤:

  1. 修改控制器逻辑:触发任务时获取任务ID(jid),传递给前端,同时去掉不必要的重定向
def index
  @q = Jobs.ransack(params[:q])
  if params_from_search_empty(@q)
    @pagy, @jobs = pagy(Jobs.all, items: Jobs::NUM_JOBS_TO_FETCH)
    if @jobs.empty? || @pagy.count.empty?
      job = FetchJobs.perform_later
      @job_jid = job.job_id # 获取Sidekiq任务ID
    end
    # 移除redirect_to,保持在当前页面由JS处理
  else
    @jobs = @q.result(distinct: true)
    @pagy, @jobs = pagy(@jobs, items: Jobs::NUM_JOBS_TO_FETCH)
  end
end

# 新增检查任务状态的接口
def check_job_status
  # 需要安装sidekiq-status gem来跟踪任务状态
  job_status = Sidekiq::Status::status(params[:jid])
  render json: { status: job_status }
end
  1. 配置路由:添加检查任务状态的路由
# config/routes.rb
get 'check_job_status', to: 'jobs#check_job_status'
  1. 前端添加轮询逻辑:在index页面中加入JS代码,定时查询任务状态
<% if @job_jid %>
  <div class="loading">正在加载数据,请稍候...</div>
  <script>
    async function checkStatus() {
      const response = await fetch(`/check_job_status?jid=<%= @job_jid %>`);
      const data = await response.json();
      
      if (data.status === 'complete') {
        window.location.reload(); // 任务完成后自动刷新页面
      } else {
        setTimeout(checkStatus, 1000); // 每秒查询一次状态
      }
    }
    checkStatus();
  </script>
<% end %>
  1. 依赖安装:执行bundle add sidekiq-status并重启Sidekiq,该gem用于跟踪任务的执行状态(pending/working/complete等)。

方案二:Action Cable实时推送完成通知

利用Rails内置的Action Cable实现WebSocket通信,任务完成后主动向前端推送通知,无需轮询。

实现步骤:

  1. 创建任务状态频道
# app/channels/job_status_channel.rb
class JobStatusChannel < ApplicationCable::Channel
  def subscribed
    # 为每个任务创建独立的消息流
    stream_from "job_status_#{params[:jid]}"
  end
end
  1. 修改Sidekiq任务:任务完成时发送广播消息
# app/workers/fetch_jobs.rb
class FetchJobs
  include Sidekiq::Worker

  def perform
    # 你的数据获取与数据库填充逻辑
    # ...
    
    # 任务完成后向对应频道发送通知
    ActionCable.server.broadcast("job_status_#{jid}", status: 'complete')
  end
end
  1. 控制器传递任务ID
def index
  @q = Jobs.ransack(params[:q])
  if params_from_search_empty(@q)
    @pagy, @jobs = pagy(Jobs.all, items: Jobs::NUM_JOBS_TO_FETCH)
    if @jobs.empty? || @pagy.count.empty?
      job = FetchJobs.perform_later
      @job_jid = job.job_id
    end
  else
    @jobs = @q.result(distinct: true)
    @pagy, @jobs = pagy(@jobs, items: Jobs::NUM_JOBS_TO_FETCH)
  end
end
  1. 前端订阅频道并处理通知
<% if @job_jid %>
  <div class="loading">正在加载数据,请稍候...</div>
  <script>
    document.addEventListener('DOMContentLoaded', () => {
      const consumer = ActionCable.createConsumer();
      
      consumer.subscriptions.create({
        channel: 'JobStatusChannel',
        jid: '<%= @job_jid %>'
      }, {
        received(data) {
          if (data.status === 'complete') {
            window.location.reload();
            consumer.disconnect(); // 完成后断开连接
          }
        }
      });
    });
  </script>
<% end %>

方案三:同步执行任务(仅适用于短耗时任务)

如果FetchJobs任务执行时间极短(几秒内),可以直接同步执行任务,避免异步带来的延迟。但注意:耗时任务会导致请求超时,不推荐用于长耗时操作。

def index
  @q = Jobs.ransack(params[:q])
  if params_from_search_empty(@q)
    # 直接同步执行任务
    FetchJobs.perform_now if Jobs.all.empty?
    
    @pagy, @jobs = pagy(Jobs.all, items: Jobs::NUM_JOBS_TO_FETCH)
  else
    @jobs = @q.result(distinct: true)
    @pagy, @jobs = pagy(@jobs, items: Jobs::NUM_JOBS_TO_FETCH)
  end
end

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 16:45:39