Class: SeoBatchPollWorker

Inherits:
Object
  • Object
show all
Includes:
Sidekiq::Job
Defined in:
app/workers/seo_batch_poll_worker.rb

Overview

Phase 2b: Poll the Batch API for completion.

Routes to the correct provider (Gemini or Anthropic) based on the
SeoBatchJob's model. Re-enqueues itself with exponential backoff
until the batch reaches a terminal state, then enqueues
SeoBatchResultsWorker to process results.

Polling schedule (exponential backoff):
2 min -> 4 min -> 8 min -> 15 min (capped)

Max polling duration: 24 hours (provider batch expiry limit).

Usage:
SeoBatchPollWorker.perform_async(batch_job_id)
SeoBatchPollWorker.perform_async(batch_job_id, { 'attempt' => 3 })

Constant Summary collapse

MAX_POLL_ATTEMPTS =

~24 hours at 15-min intervals

120
MIN_BACKOFF_SECONDS =

2 minutes

120
MAX_BACKOFF_SECONDS =

15 minutes

900

Instance Method Summary collapse

Instance Method Details

#perform(batch_job_id, options = {}) ⇒ Object

Parameters:

  • batch_job_id (Integer)
  • options (Hash) (defaults to: {})

    Job arguments

Options Hash (options):

  • attempt (Integer)

    Current poll attempt (drives exponential backoff)



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'app/workers/seo_batch_poll_worker.rb', line 31

def perform(batch_job_id, options = {})
  attempt = (options[:attempt] || 1).to_i

  batch_job = SeoBatchJob.find(batch_job_id)

  unless batch_job.processing?
    log_info "Batch job #{batch_job_id} is #{batch_job.status} — stopping poll"
    return
  end

  if attempt > MAX_POLL_ATTEMPTS
    batch_job.mark_failed!("Polling timed out after #{MAX_POLL_ATTEMPTS} attempts")
    log_error "Polling timed out for batch job #{batch_job_id}"
    return
  end

  if batch_job.gemini?
    poll_gemini(batch_job, attempt)
  else
    poll_anthropic(batch_job, attempt)
  end
rescue Seo::GeminiBatchClient::BatchError, Seo::AnthropicBatchClient::BatchError => e
  log_error "Poll failed: #{e.message}"
  if attempt < MAX_POLL_ATTEMPTS
    self.class.perform_in(MAX_BACKOFF_SECONDS, batch_job_id, { 'attempt' => attempt + 1 })
  else
    batch_job.mark_failed!("Poll error after #{attempt} attempts: #{e.message}")
  end
end