Question

I am encountering errors when I am using Ruby's File.exist? method in middleware. I have no idea why.

This is the background. I am improving some old webapp which hosts around 100GB of photos and growing. I need to replicate production environment on my computer, but I don't want to download all those files. It would be great if app could check if given file exists in my filesystem and either serve it or redirect to production server.

I thought I could do simple rack app as middleware:

require 'rack/utils'

class FetchMissingPicturesMiddleware
  def initialize(app)
    @app = app
  end

  def call(env)
    if env["PATH_INFO"].starts_with? "/system/attachments/" && !File.exist?(Rails.root.join('public').join(env["PATH_INFO"][1..-1]))
      [307, { "Location" => "http://production.example.com" + env["PATH_INFO"] }, ""]
    else
      @app.call(env)
    end
  end
end

However, following error is thrown (not always, for some pictures it just works):

[2012-11-26 14:28:12] ERROR ThreadError: thread 0x10aed55e8 tried to join itself
    /Users/skale/.rvm/gems/ruby-1.8.7-p371/gems/actionpack-2.3.9/lib/action_controller/reloader.rb:31:in `lock'
    /Users/skale/.rvm/gems/ruby-1.8.7-p371/gems/actionpack-2.3.9/lib/action_controller/reloader.rb:31:in `run'
    /Users/skale/.rvm/gems/ruby-1.8.7-p371/gems/actionpack-2.3.9/lib/action_controller/dispatcher.rb:108:in `call'
    /Users/skale/.rvm/gems/ruby-1.8.7-p371/gems/rails-2.3.9/lib/rails/rack/static.rb:31:in `call'
    /Users/skale/.rvm/gems/ruby-1.8.7-p371/gems/rack-1.1.3/lib/rack/urlmap.rb:47:in `call'
    /Users/skale/.rvm/gems/ruby-1.8.7-p371/gems/rack-1.1.3/lib/rack/urlmap.rb:41:in `each'
    /Users/skale/.rvm/gems/ruby-1.8.7-p371/gems/rack-1.1.3/lib/rack/urlmap.rb:41:in `call'
    /Users/skale/.rvm/gems/ruby-1.8.7-p371/gems/rails-2.3.9/lib/rails/rack/log_tailer.rb:17:in `call'
    /Users/skale/.rvm/gems/ruby-1.8.7-p371/gems/rack-1.1.3/lib/rack/content_length.rb:13:in `call'
    /Users/skale/.rvm/gems/ruby-1.8.7-p371/gems/rack-1.1.3/lib/rack/handler/webrick.rb:48:in `service'
    /Users/skale/.rvm/rubies/ruby-1.8.7-p371/lib/ruby/1.8/webrick/httpserver.rb:104:in `service'
    /Users/skale/.rvm/rubies/ruby-1.8.7-p371/lib/ruby/1.8/webrick/httpserver.rb:65:in `run'
    /Users/skale/.rvm/rubies/ruby-1.8.7-p371/lib/ruby/1.8/webrick/server.rb:173:in `start_thread'
    /Users/skale/.rvm/rubies/ruby-1.8.7-p371/lib/ruby/1.8/webrick/server.rb:162:in `start'
    /Users/skale/.rvm/rubies/ruby-1.8.7-p371/lib/ruby/1.8/webrick/server.rb:162:in `start_thread'
    /Users/skale/.rvm/rubies/ruby-1.8.7-p371/lib/ruby/1.8/webrick/server.rb:95:in `start'
    /Users/skale/.rvm/rubies/ruby-1.8.7-p371/lib/ruby/1.8/webrick/server.rb:92:in `each'
    /Users/skale/.rvm/rubies/ruby-1.8.7-p371/lib/ruby/1.8/webrick/server.rb:92:in `start'
    /Users/skale/.rvm/rubies/ruby-1.8.7-p371/lib/ruby/1.8/webrick/server.rb:23:in `start'
    /Users/skale/.rvm/rubies/ruby-1.8.7-p371/lib/ruby/1.8/webrick/server.rb:82:in `start'
    /Users/skale/.rvm/gems/ruby-1.8.7-p371/gems/rack-1.1.3/lib/rack/handler/webrick.rb:14:in `run'
    /Users/skale/.rvm/gems/ruby-1.8.7-p371/gems/rails-2.3.9/lib/commands/server.rb:111
    script/server:6:in `require'
    script/server:6

I am surprised with this issue because it's run inside mutex provided by Rack::Lock. Moving this middleware before Rack::Lock does not help. After removing File.exist? errors are gone. This is Ruby 1.8.7 with freshest (1.8.24) rubygems on Rails 2.3.9.

Thanks for your help.

Was it helpful?

Solution

Actually, the problem was bit different. The last element of the response array should be an array too.

wrong:

[307, { "Location" => "http://production.example.com" + env["PATH_INFO"] }, ""]

good:

[307, { "Location" => "http://production.example.com" + env["PATH_INFO"] }, []]
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top