-
Notifications
You must be signed in to change notification settings - Fork 21.9k
Fail more gracefully from ActiveStorage missing file exceptions #33666
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fail more gracefully from ActiveStorage missing file exceptions #33666
Conversation
_, io = blobs.get_blob(container, key) | ||
io.force_encoding(Encoding::BINARY) | ||
rescue Azure::Core::Http::HTTPError => e | ||
raise e unless e.type == "BlobNotFound" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let’s use bare raise
instead of raise e
to avoid munging the backtrace:
if e.type == "BlobNotFound"
raise ActiveStorage::FileNotFoundError
else
raise
end
rescue Azure::Core::Http::HTTPError => e | ||
raise e unless e.type == "BlobNotFound" | ||
raise ActiveStorage::FileNotFoundError | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we extract a private handle_errors
method to avoid duplicating the error handling logic in download
and download_chunk
?
def download_chunk(key, range)
instrument :download_chunk, key: key, range: range do
handle_errors do
_, io = blobs.get_blob(container, key, start_range: range.begin, end_range: range.exclude_end? ? range.end - 1 : range.end)
io.force_encoding(Encoding::BINARY)
end
end
end
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was half tempted to put such a private method on the parent class (taking a service specific exception as an argument) but worried it was gonna be too much magic. Is this just needed because of the extra type checking needed for Azure errors? (Related bug fix PR #33667 that should probably do it the same way…)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wouldn’t put it on the parent class. It’s a service-specific method.
raise | ||
end | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You don’t need the begin
/end
block here:
def handle_errors
yield
rescue Azure::Core::Http::HTTPError => e
# ...
end
end | ||
rescue Errno::ENOENT | ||
raise ActiveStorage::FileNotFoundError | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto: you don’t need the begin
/end
block here.
Last thing: can you please squash your commits? I think two are appropriate: one for rescuing I also think these changes merit separate changelog entries, since they're independent:
|
`ActiveStorage::Blob#download` and `ActiveStorage::Blob#open` raise `ActiveStorage::FileNotFoundError` when the corresponding file is missing from the storage service. Services translate service-specific missing object exceptions (e.g. `Google::Cloud::NotFoundError` for the GCS service and `Errno::ENOENT` for the disk service) into `ActiveStorage::FileNotFoundError`.
`ActiveStorage::DiskController#show` generates a 404 Not Found response when the requested file is missing from the disk service. It previously raised `Errno::ENOENT`.
6286b76
to
22efb2e
Compare
Done 👍 Is there anything to do about the errors raised in |
The rails/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb Lines 179 to 188 in cdee520
I’m not immediately sure what we can do about that. I’m going to think about it and merge this in the meantime. |
Fail more gracefully from ActiveStorage missing file exceptions rails/rails#33666
This PR translates service-specific missing object exceptions into one generic
ActiveStorage::FileNotFoundError
so that the application can fail more gracefully when a missing file is accessed. Specifically, this PR letsDiskController
rescue this error and respond with 404 instead of 500. This improves the development experience especially when working, indevelopment
, with a database of Blob records that point to files in theproduction
service.Outstanding question
RepresentationsController
does not presently handleActiveStorage::FileNotFoundError
, since @georgeclaghorn argued it truly is exceptional for the service not to have a file that corresponds to a specific blob in the database. I don’t disagree with this, but hope we can nevertheless find a way to reduce the flood of stack traces that fill ourdevelopment
logs when loading an index view that tries to display many thumbnails of images stored in ourproduction
service.Related issue
Resolves #33647