falcon icon indicating copy to clipboard operation
falcon copied to clipboard

Constant loading issue in development (with async-cable)

Open nativestranger opened this issue 1 month ago • 3 comments

Hey! Thanks for this gem, it's awesome! I've been using it in production just fine, but I'm having issues in development that are seemingly related to auto reloading and constant definitions.

Below logs a recurrent issue that causes 500s in my falcon responses occasionally... my current fix is to just stop and restart the server.

This app is using a standard async-cable + falcon setup on Rails 8.1 (ruby 3.4.7). The line in SetCurrentRequestDetails#set_request_details that is failing is just

Current.user = current_user (using current_user from Devise)

Completed 500 Internal Server Error in 5ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.6ms)



NameError (uninitialized constant User):

app/controllers/concerns/set_current_request_details.rb:15:in 'SetCurrentRequestDetails#set_request_details'
Started GET "/cable" for ::1 at 2025-11-07 15:14:22 -0500
   13h     warn: Async::Cable::Middleware [oid=0x1462b8] [ec=0x174808] [pid=56717] [2025-11-07 15:14:22 -0500]
               | Abnormal client failure!
               | uninitialized constant User
               |   NameError: uninitialized constant User (NameError)
               |
               |         Object.const_get(camel_cased_word)
               |               ^^^^^^^^^^
               |   Did you mean?  Users
               |   → vendor/bundle/ruby/3.4.0/gems/activesupport-8.1.0.rc1/lib/active_support/inflector/methods.rb:290 in 'Module#const_get'
               |     vendor/bundle/ruby/3.4.0/gems/activesupport-8.1.0.rc1/lib/active_support/inflector/methods.rb:290 in 'ActiveSupport::Inflector#constantize'
               |     vendor/bundle/ruby/3.4.0/gems/activesupport-8.1.0.rc1/lib/active_support/core_ext/string/inflections.rb:74 in 'String#constantize'
               |     vendor/bundle/ruby/3.4.0/gems/devise-4.9.4/lib/devise.rb:327 in 'Devise::Getter#get'
               |     vendor/bundle/ruby/3.4.0/gems/devise-4.9.4/lib/devise/mapping.rb:83 in 'Devise::Mapping#to'
               |     vendor/bundle/ruby/3.4.0/gems/devise-4.9.4/lib/devise.rb:496 in 'block (2 levels) in Warden::SessionSerializer#configure_warden!'
               |     vendor/bundle/ruby/3.4.0/gems/warden-1.2.9/lib/warden/session_serializer.rb:35 in 'Warden::SessionSerializer#fetch'
               |     vendor/bundle/ruby/3.4.0/gems/warden-1.2.9/lib/warden/proxy.rb:224 in 'Warden::Proxy#user'
               |     app/channels/application_cable/connection.rb:21 in 'ApplicationCable::Connection#find_verified_user'
               |     app/channels/application_cable/connection.rb:11 in 'ApplicationCable::Connection#connect'
               |     vendor/bundle/ruby/3.4.0/gems/actioncable-next-0.2.0/lib/action_cable/connection/base.rb:92 in 'ActionCable::Connection::Base#handle_open'
               |     vendor/bundle/ruby/3.4.0/gems/async-cable-0.3.0/lib/async/cable/middleware.rb:44 in 'Async::Cable::Middleware#handle_incoming_websocket'
               |     vendor/bundle/ruby/3.4.0/gems/async-cable-0.3.0/lib/async/cable/middleware.rb:31 in 'block in Async::Cable::Middleware#call'
               |     vendor/bundle/ruby/3.4.0/gems/async-websocket-0.30.0/lib/async/websocket/adapters/http.rb:41 in 'block in Async::WebSocket::Adapters::HTTP.open'
               |     vendor/bundle/ruby/3.4.0/gems/async-http-0.91.0/lib/async/http/body/hijack.rb:39 in 'Async::HTTP::Body::Hijack#call'
               |     vendor/bundle/ruby/3.4.0/gems/rack-3.2.3/lib/rack/body_proxy.rb:56 in 'Method#call'
               |     vendor/bundle/ruby/3.4.0/gems/rack-3.2.3/lib/rack/body_proxy.rb:56 in 'Rack::BodyProxy#method_missing'
               |     vendor/bundle/ruby/3.4.0/gems/rack-3.2.3/lib/rack/body_proxy.rb:56 in 'Rack::BodyProxy#method_missing'
               |     vendor/bundle/ruby/3.4.0/gems/protocol-http-0.54.0/lib/protocol/http/body/streamable.rb:63 in 'block in Protocol::HTTP::Body::Streamable::Output#schedule'
               |     vendor/bundle/ruby/3.4.0/gems/async-2.34.0/lib/async/task.rb:207 in 'block in Async::Task#run'
               |     vendor/bundle/ruby/3.4.0/gems/async-2.34.0/lib/async/task.rb:452 in 'block in Async::Task#schedule'

Happy to provide more info as we track this down.

nativestranger avatar Nov 07 '25 20:11 nativestranger

@fxn do you have any thoughts on why this might be happening?

ioquatix avatar Nov 12 '25 12:11 ioquatix

Hey! Quick reply.

At first sight it sounds related to autoloading/reloading, but it is interesting that the exception is a bare NameError. That means the autoloader is not managing that constant at the moment, otherwise it would be a Zeitwerk::Error or subclass.

@nativestranger yes, please, the more context we have, the better.

In case it helps, if you throw

Rails.autoloaders.log!

into config/application.rb, within the application class body, you'll be able to watch the autoloaders activity.

fxn avatar Nov 12 '25 12:11 fxn

@nativestranger blind shot: is it the case that every time this happens there has been an edit? that is, is the app always reloading?

fxn avatar Nov 12 '25 13:11 fxn