Rails中如何通过API从前端获取Sidekiq任务进度信息?
Hey there! Let me break down how to get individual job progress from your Sidekiq workers (using the sidekiq-status gem) into your frontend—since the /sidekiq/stats endpoint only gives you global Sidekiq metrics, not per-job details.
Step 1: Expose a Custom API Endpoint
The sidekiq-status gem doesn’t automatically expose an API for fetching job statuses, so you’ll need to create a small controller in your Rails app to bridge the gap:
Create app/controllers/api/job_statuses_controller.rb:
class Api::JobStatusesController < ApplicationController # Skip CSRF verification if your frontend is making cross-origin requests or using an API-only setup skip_before_action :verify_authenticity_token, only: [:show] def show job_id = params[:id] # Fetch the basic status (e.g., 'queued', 'working', 'complete', 'failed') status = Sidekiq::Status::get(job_id) if status # Fetch all metadata associated with the job (including progress) job_metadata = Sidekiq::Status::get_all(job_id) render json: { job_id: job_id, status: status, progress: job_metadata['progress'] || 0, message: job_metadata['message'] || '', # Add any other custom metadata you stored in the worker result: job_metadata['result'] } else render json: { error: "Job not found or has completed/expired" }, status: :not_found end end end
Step 2: Add a Route for the API
Update your config/routes.rb to map the endpoint:
namespace :api do get '/job_statuses/:id', to: 'job_statuses#show' end
Step 3: Update Your Worker to Track Progress
Make sure your worker includes the sidekiq-status module and updates progress during execution:
class MyWorker include Sidekiq::Worker include Sidekiq::Status::Worker # Required to track status/progress def perform(some_task_arg) total_steps = 100 # Initialize progress with total steps and a starting message progress(0, total_steps, "Initializing task...") total_steps.times do |step| # Your actual task logic goes here sleep(0.1) # Simulate work # Update progress after each step progress(step + 1, total_steps, "Completed step #{step + 1}/#{total_steps}") end # Optional: Store a custom result when the job finishes store({ result: "Task completed successfully!" }) end end
Step 4: Fetch Progress from the Frontend
Use fetch or a library like Axios to poll the API endpoint (since progress updates over time):
// Fetch a single job status async function fetchJobStatus(jobId) { try { const response = await fetch(`/api/job_statuses/${jobId}`); if (!response.ok) throw new Error("Failed to fetch job status"); return await response.json(); } catch (error) { console.error("Error fetching job status:", error); return null; } } // Poll the status at intervals until the job finishes function pollJobProgress(jobId, intervalMs = 2000) { const intervalId = setInterval(async () => { const status = await fetchJobStatus(jobId); if (!status) { clearInterval(intervalId); return; } // Update your frontend UI here (e.g., progress bar, status message) console.log(`Progress: ${status.progress}% | Status: ${status.status}`); // Stop polling when the job is done or failed if (status.status === "complete" || status.status === "failed") { clearInterval(intervalId); console.log("Job finished:", status.result || status.status); } }, intervalMs); return intervalId; } // Usage: Start polling when you have the job ID (returned when enqueuing the worker) const jobId = "your-job-id-here"; pollJobProgress(jobId);
Why /sidekiq/stats Doesn’t Work for This
The /sidekiq/stats endpoint returns global Sidekiq metrics (total processed jobs, busy workers, etc.)—it doesn’t have any data about individual job progress. The sidekiq-status gem stores per-job metadata in Redis, so we need to use its helper methods (Sidekiq::Status::get, Sidekiq::Status::get_all) to retrieve that data and expose it via our custom API.
内容的提问来源于stack exchange,提问作者user5639287

