Skip to content

Commit e15be8c

Browse files
authored
Merge pull request rails#53770 from Earlopain/aj-deserialization-name-error
Raise a more specific error when the job class can't be instantiated
2 parents a87bbdf + 5a04667 commit e15be8c

File tree

4 files changed

+30
-1
lines changed

4 files changed

+30
-1
lines changed

activejob/CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,9 @@
1+
* Raise a more specific error during deserialization when a previously serialized job class is now unknown.
2+
3+
`ActiveJob::UnknownJobClassError` will be raised instead of a more generic
4+
`NameError` to make it easily possible for adapters to tell if the `NameError`
5+
was raised during job execution or deserialization.
6+
7+
*Earlopain*
18

29
Please check [8-0-stable](https://github.com/rails/rails/blob/8-0-stable/activejob/CHANGELOG.md) for previous changes.

activejob/lib/active_job.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ module ActiveJob
3939
autoload :Arguments
4040
autoload :DeserializationError, "active_job/arguments"
4141
autoload :SerializationError, "active_job/arguments"
42+
autoload :UnknownJobClassError, "active_job/core"
4243
autoload :EnqueueAfterTransactionCommit
4344

4445
eager_autoload do

activejob/lib/active_job/core.rb

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
# frozen_string_literal: true
22

33
module ActiveJob
4+
# Raised during job payload deserialization when it references an uninitialized job class.
5+
class UnknownJobClassError < NameError
6+
def initialize(job_class_name)
7+
super("Failed to instantiate job, class `#{job_class_name}` doesn't exist", job_class_name)
8+
end
9+
end
10+
411
# = Active Job \Core
512
#
613
# Provides general behavior that will be included into every Active Job
@@ -60,7 +67,10 @@ def successfully_enqueued?
6067
module ClassMethods
6168
# Creates a new job instance from a hash created with +serialize+
6269
def deserialize(job_data)
63-
job = job_data["job_class"].constantize.new
70+
job_class = job_data["job_class"].safe_constantize
71+
raise UnknownJobClassError, job_data["job_class"] unless job_class
72+
73+
job = job_class.new
6474
job.deserialize(job_data)
6575
job
6676
end

activejob/test/cases/job_serialization_test.rb

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,17 @@ class JobSerializationTest < ActiveSupport::TestCase
3838
assert_equal h2.serialize, h3.serialize
3939
end
4040

41+
test "deserialize raises a specific exception on unknown `job_class`" do
42+
payload = HelloJob.new.serialize
43+
44+
# Simulate the job class being missing, for example during rolling deploys when
45+
# the server enqueues a new job but the job processor hasn't been restarted yet.
46+
payload["job_class"] = "IDontExist"
47+
assert_raises(ActiveJob::UnknownJobClassError) do
48+
HelloJob.deserialize(payload)
49+
end
50+
end
51+
4152
test "deserialize sets locale" do
4253
job = HelloJob.new
4354
job.deserialize "locale" => "es"

0 commit comments

Comments
 (0)