Class: Postburner::OrphanedJob
- Inherits:
-
Job
- Object
- ActiveRecord::Base
- ApplicationRecord
- Job
- Postburner::OrphanedJob
- Defined in:
- app/models/postburner/orphaned_job.rb
Overview
Inert STI placeholder loaded when a Postburner::Job row’s ‘type` column references a class that no longer exists in the application.
## Why readonly?
Rails’ ‘ensure_proper_type` (called via `save`/`update`) would overwrite the original `type` value with `’Postburner::OrphanedJob’‘, permanently destroying the record of which class was missing. `readonly?` returning true prevents all `save`/`update` paths and therefore blocks `ensure_proper_type` from running.
Rails’ ‘instantiate` reads the `type` column verbatim when loading records from the database and does NOT call `ensure_proper_type`, so the original class name is preserved on load. This class is only ever instantiated via the `find_sti_class` fallback in Job, never created directly.
## Why remove! is overridden here
In Rails 8.1+, ‘update_column` respects `readonly?` and raises `ActiveRecord::ReadOnlyRecord`. The base `Commands#remove!` calls `update_column(:removed_at, …)` — so it would be blocked too. This subclass overrides `remove!` to use `self.class.where(id: self.id).update_all(…)` which operates at the relation level (bypasses both `readonly?` and all instance callbacks) while still soft-deleting the row. Admins can therefore safely soft-remove orphaned rows without restoring the missing class.
## Usage
This class is loaded automatically by Job.find_sti_class when a row’s type is unresolvable. You should never instantiate it directly in application code.
Instance Attribute Summary
Attributes inherited from Job
#args, #attempt_count, #attempting_at, #attempts, #bkid, #duration, #errata, #error_count, #id, #lag, #log_count, #logs, #processed_at, #processing_at, #queued_at, #removed_at, #run_at, #sid, #type
Instance Method Summary collapse
-
#missing_class_name ⇒ String
Returns the original class name stored in the ‘type` column — the deleted or renamed class that this placeholder stands in for.
-
#orphaned? ⇒ Boolean
Always true; identifies this instance as an orphaned placeholder.
-
#perform ⇒ Object
Raises Job::OrphanedJobError because the original job class no longer exists and there is no implementation to run.
-
#queue! ⇒ Object
(also: #requeue!)
Raises Job::OrphanedJobError because re-enqueuing a job whose class is gone would only produce another unperformable entry.
-
#readonly? ⇒ Boolean
Prevents saves that would allow Rails’ ensure_proper_type to overwrite the original ‘type` value with ’Postburner::OrphanedJob’.
-
#remove! ⇒ void
Soft-deletes this orphaned row by setting ‘removed_at`, bypassing the `readonly?` guard via a relation-level `update_all` call (which does not go through instance save/update and therefore does not trigger `ensure_proper_type` either).
Methods inherited from Job
#bk, #bk!, #bk=, #destroy, #destroy!, find_sti_class
Methods included from Statistics
#elapsed_ms, #intended_at, #stats
Methods included from Execution
Methods included from Insertion
Methods included from Commands
Methods included from Logging
#log, #log!, #log_exception, #log_exception!
Methods included from Properties
#priority, #queue_name, #retry_delay_for_attempt, #should_retry?, #ttr, #tube_name
Instance Method Details
#missing_class_name ⇒ String
Returns the original class name stored in the ‘type` column — the deleted or renamed class that this placeholder stands in for.
51 52 53 |
# File 'app/models/postburner/orphaned_job.rb', line 51 def missing_class_name self.type.to_s end |
#orphaned? ⇒ Boolean
Always true; identifies this instance as an orphaned placeholder.
59 |
# File 'app/models/postburner/orphaned_job.rb', line 59 def orphaned? = true |
#perform ⇒ Object
Raises Job::OrphanedJobError because the original job class no longer exists and there is no implementation to run.
66 67 68 69 |
# File 'app/models/postburner/orphaned_job.rb', line 66 def perform(*) raise Postburner::Job::OrphanedJobError, "Cannot perform orphaned job ##{self.id}: class '#{self.missing_class_name}' no longer exists" end |
#queue! ⇒ Object Also known as: requeue!
Raises Job::OrphanedJobError because re-enqueuing a job whose class is gone would only produce another unperformable entry.
76 77 78 79 |
# File 'app/models/postburner/orphaned_job.rb', line 76 def queue!(*) raise Postburner::Job::OrphanedJobError, "Cannot enqueue orphaned job ##{self.id}: class '#{self.missing_class_name}' no longer exists" end |
#readonly? ⇒ Boolean
Prevents saves that would allow Rails’ ensure_proper_type to overwrite the original ‘type` value with ’Postburner::OrphanedJob’.
105 |
# File 'app/models/postburner/orphaned_job.rb', line 105 def readonly? = true |
#remove! ⇒ void
This method returns an undefined value.
Soft-deletes this orphaned row by setting ‘removed_at`, bypassing the `readonly?` guard via a relation-level `update_all` call (which does not go through instance save/update and therefore does not trigger `ensure_proper_type` either).
Idempotent: does nothing if already removed.
91 92 93 94 95 96 97 98 |
# File 'app/models/postburner/orphaned_job.rb', line 91 def remove! return if self.removed_at self.delete! now = Time.current self.class.where(id: self.id).update_all(removed_at: now) self.removed_at = now end |