Class: SeoBatchJob
Overview
Tracks a single batch submission to the Gemini or Anthropic Batch API.
Lifecycle:
collecting -> submitting -> processing -> completed
-> failed
The nightly pipeline creates one SeoBatchJob per run. It progresses through:
- SeoBatchCollectorWorker builds prompts for each page (status: collecting)
- SeoBatchSubmitWorker submits to Batch API (status: submitting -> processing)
- SeoBatchPollWorker monitors until done
- SeoBatchResultsWorker saves results (status: completed)
Provider routing:
- Gemini models -> Gemini Batch API (50% discount)
- Claude models -> Anthropic Message Batches API (50% discount)
== Schema Information
Table name: seo_batch_jobs
Database name: primary
id :bigint not null, primary key
completed_at :datetime
errored_count :integer default(0)
expired_count :integer default(0)
metadata :jsonb
model :string default("claude-sonnet-4-5"), not null
status :string default("collecting"), not null
submitted_at :datetime
succeeded_count :integer default(0)
total_pages :integer default(0)
created_at :datetime not null
updated_at :datetime not null
ai_batch_id :string
Indexes
index_seo_batch_jobs_on_ai_batch_id (ai_batch_id) UNIQUE
index_seo_batch_jobs_on_status (status)
Constant Summary
collapse
- STATUSES =
%w[collecting submitting processing completed failed].freeze
Instance Attribute Summary collapse
Class Method Summary
collapse
Instance Method Summary
collapse
ransackable_associations, ransackable_attributes, ransackable_scopes, ransortable_attributes, #to_relation
#publish_event
Instance Attribute Details
#model ⇒ Object
49
|
# File 'app/models/seo_batch_job.rb', line 49
validates :model, presence: true
|
#status ⇒ Object
48
|
# File 'app/models/seo_batch_job.rb', line 48
validates :status, inclusion: { in: STATUSES }
|
Class Method Details
.active ⇒ ActiveRecord::Relation<SeoBatchJob>
A relation of SeoBatchJobs that are active. Active Record Scope
51
|
# File 'app/models/seo_batch_job.rb', line 51
scope :active, -> { where(status: %w[collecting submitting processing]) }
|
.completed ⇒ ActiveRecord::Relation<SeoBatchJob>
A relation of SeoBatchJobs that are completed. Active Record Scope
52
|
# File 'app/models/seo_batch_job.rb', line 52
scope :completed, -> { where(status: 'completed') }
|
Instance Method Details
#anthropic? ⇒ Boolean
61
|
# File 'app/models/seo_batch_job.rb', line 61
def anthropic? = model.to_s.start_with?('claude-')
|
#collecting? ⇒ Boolean
54
|
# File 'app/models/seo_batch_job.rb', line 54
def collecting? = status == 'collecting'
|
#completed? ⇒ Boolean
57
|
# File 'app/models/seo_batch_job.rb', line 57
def completed? = status == 'completed'
|
#failed? ⇒ Boolean
58
|
# File 'app/models/seo_batch_job.rb', line 58
def failed? = status == 'failed'
|
#gemini? ⇒ Boolean
60
|
# File 'app/models/seo_batch_job.rb', line 60
def gemini? = model.to_s.start_with?('gemini-')
|
#items ⇒ ActiveRecord::Relation<SeoBatchItem>
46
|
# File 'app/models/seo_batch_job.rb', line 46
has_many :items, class_name: 'SeoBatchItem', dependent: :destroy
|
#mark_completed!(succeeded: 0, errored: 0, expired: 0) ⇒ Object
81
82
83
84
85
86
87
88
89
|
# File 'app/models/seo_batch_job.rb', line 81
def mark_completed!(succeeded: 0, errored: 0, expired: 0)
update!(
status: 'completed',
succeeded_count: succeeded,
errored_count: errored,
expired_count: expired,
completed_at: Time.current
)
end
|
#mark_failed!(error_message) ⇒ Object
91
92
93
94
95
96
97
|
# File 'app/models/seo_batch_job.rb', line 91
def mark_failed!(error_message)
update!(
status: 'failed',
completed_at: Time.current,
metadata: metadata.merge('error' => error_message)
)
end
|
#mark_submitted!(provider_batch_id:, provider: nil, extra_metadata: {}) ⇒ Object
67
68
69
70
71
72
73
74
75
76
77
78
79
|
# File 'app/models/seo_batch_job.rb', line 67
def mark_submitted!(provider_batch_id:, provider: nil, extra_metadata: {})
merged = metadata
.merge('provider' => provider || inferred_provider)
.merge()
update!(
status: 'processing',
ai_batch_id: provider_batch_id,
submitted_at: Time.current,
total_pages: items.count,
metadata: merged
)
end
|
#processing? ⇒ Boolean
56
|
# File 'app/models/seo_batch_job.rb', line 56
def processing? = status == 'processing'
|
#provider_batch_id ⇒ Object
63
64
65
|
# File 'app/models/seo_batch_job.rb', line 63
def provider_batch_id
ai_batch_id
end
|
#submitting? ⇒ Boolean
55
|
# File 'app/models/seo_batch_job.rb', line 55
def submitting? = status == 'submitting'
|