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

Merged
merged 2 commits into from Aug 23, 2018

Conversation

Projects
None yet
2 participants
@cbothner
Contributor

cbothner commented Aug 20, 2018

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 lets DiskController rescue this error and respond with 404 instead of 500. This improves the development experience especially when working, in development, with a database of Blob records that point to files in the production service.

Outstanding question

RepresentationsController does not presently handle ActiveStorage::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 our development logs when loading an index view that tries to display many thumbnails of images stored in our production service.

Related issue

Resolves #33647

@georgeclaghorn georgeclaghorn self-assigned this Aug 20, 2018

Show outdated Hide outdated activestorage/lib/active_storage/service/azure_storage_service.rb
Show outdated Hide outdated activestorage/lib/active_storage/service/azure_storage_service.rb
Show outdated Hide outdated activestorage/lib/active_storage/service/azure_storage_service.rb
Show outdated Hide outdated activestorage/lib/active_storage/service/disk_service.rb
@georgeclaghorn

This comment has been minimized.

Show comment
Hide comment
@georgeclaghorn

georgeclaghorn Aug 21, 2018

Member

Last thing: can you please squash your commits? I think two are appropriate: one for rescuing Errno::ENOENT in DiskController and one for translating service-specific missing object exceptions.

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.

Member

georgeclaghorn commented Aug 21, 2018

Last thing: can you please squash your commits? I think two are appropriate: one for rescuing Errno::ENOENT in DiskController and one for translating service-specific missing object exceptions.

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.

cbothner added some commits Aug 18, 2018

Translate service-specific missing object exceptions into a generic one
`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`.
Respond with 404 in ActiveStorage::DiskController#show when file missing
`ActiveStorage::DiskController#show` generates a 404 Not Found response when
the requested file is missing from the disk service. It previously raised
`Errno::ENOENT`.
@cbothner

This comment has been minimized.

Show comment
Hide comment
@cbothner

cbothner Aug 21, 2018

Contributor

Done 👍

Is there anything to do about the errors raised in RepresentationsController for the sake of developer experience, or is that inappropriate to handle at the framework level?

Contributor

cbothner commented Aug 21, 2018

Done 👍

Is there anything to do about the errors raised in RepresentationsController for the sake of developer experience, or is that inappropriate to handle at the framework level?

@georgeclaghorn

This comment has been minimized.

Show comment
Hide comment
@georgeclaghorn

georgeclaghorn Aug 23, 2018

Member

The DebugExceptions middleware logs the full backtrace if none of the lines in the trace come from the application, which is the case for ActiveStorage::FileNotFoundErrors triggered by requests to RepresentationsController:

trace = wrapper.application_trace
trace = wrapper.framework_trace if trace.empty?
ActiveSupport::Deprecation.silence do
logger.fatal " "
logger.fatal "#{exception.class} (#{exception.message}):"
log_array logger, exception.annoted_source_code if exception.respond_to?(:annoted_source_code)
logger.fatal " "
log_array logger, trace
end

I’m not immediately sure what we can do about that. I’m going to think about it and merge this in the meantime.

Member

georgeclaghorn commented Aug 23, 2018

The DebugExceptions middleware logs the full backtrace if none of the lines in the trace come from the application, which is the case for ActiveStorage::FileNotFoundErrors triggered by requests to RepresentationsController:

trace = wrapper.application_trace
trace = wrapper.framework_trace if trace.empty?
ActiveSupport::Deprecation.silence do
logger.fatal " "
logger.fatal "#{exception.class} (#{exception.message}):"
log_array logger, exception.annoted_source_code if exception.respond_to?(:annoted_source_code)
logger.fatal " "
log_array logger, trace
end

I’m not immediately sure what we can do about that. I’m going to think about it and merge this in the meantime.

@georgeclaghorn georgeclaghorn merged commit dc001db into rails:master Aug 23, 2018

2 checks passed

codeclimate All good!
Details
continuous-integration/travis-ci/pr The Travis CI build passed
Details

@cbothner cbothner deleted the cbothner:fail-gracefully-from-activestorage-file-not-found branch Aug 23, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment