Rails Active Job that polls an AI video API: retry_job and wait
An Active Job on Solid Queue reads Sume's job status once and calls retry_job with wait from next_poll_after_seconds until the video job is terminal.

On Rails 8 with Solid Queue (the default Active Job backend), poll an AI video the Active Job way: PollVideoJob.set(wait: 15.seconds).perform_later(job_id), and inside perform, retry_job(wait: n) or self.class.set(wait: n).perform_later(...) when the job is still running. Active Job is backend-neutral, so the same class runs on Sidekiq or GoodJob unchanged. The wait comes from Sume's next_poll_after_seconds on GET /v1/jobs/{id}/status (Sume jobs guide, read 2026-10-06).
If you want Sidekiq's native API instead, see the Sidekiq version of this poller.
What does the job class look like?
The class below re-enqueues itself with an attempt counter, so Active Job's own error retries (retry_on) only count real failures such as network errors.
require "net/http"
require "json"
class PollVideoJob < ApplicationJob
queue_as :default
retry_on Net::ReadTimeout, Net::OpenTimeout, wait: 30.seconds, attempts: 5
def perform(job_id, n = 0)
uri = URI("https://api.sume.com/v1/jobs/#{job_id}/status")
req = Net::HTTP::Get.new(uri, "Authorization" => "Bearer #{ENV.fetch('SUME_API_KEY')}")
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |h| h.request(req) }
raise "sume status #{res.code}" unless res.is_a?(Net::HTTPSuccess)
s = JSON.parse(res.body)
if s["terminal"]
Video.find_by!(sume_job_id: job_id).update!(state: s["sume_status"])
elsif n < 120
wait = (s["next_poll_after_seconds"] || 15).to_i
self.class.set(wait: wait.seconds).perform_later(job_id, n + 1)
end
end
endWhere does the paid request go?
Into a separate job or a controller action. Send Idempotency-Key: video-#{video.id} on POST /v1/videos and store the returned id on the row before you enqueue the first poll. If that save fails after the POST succeeded, re-sending with the same key returns the original job rather than a second charge.
Does a retry of the poller bill a second clip?
No, as long as the poller only reads. Keep the paid POST /v1/videos in a separate step with an Idempotency-Key you own, and let the poller use GET /v1/jobs/{id}/status. A client-side give-up never cancels the render; Sume's jobs guide says the job keeps running, so store the job id and read it again later instead of submitting a second time.
Sources
Related posts
More in Developers
- Read Sume TTS raw PCM in Python: f32le samples at 24 kHz
Ask the TTS Router for container raw, 24000 Hz and pcm_f32le, then load the samples with the standard library for DSP or a custom player.
- Record the Idempotency-Key before you POST a Sume video job
A worker that dies after submitting a video job loses the job id. Write the key to a ledger first, then POST; a retry returns the same job. Tested SQLite code.
- Redact sume_live_ API keys from Python logs with a handler filter
A logging.Filter on a logger skips records from child loggers. Put the redaction filter on the handler so a sume_live_ key never reaches the log file.
- Redis sorted set scheduler for AI video job polling in Python
Keep video job ids in a Redis ZSET scored by next-poll time, claim due ids with ZREM so no two workers poll one job, reschedule by next_poll_after_seconds.
Written by Sume