lib/geminabox/server.rb in geminabox-0.13.7 vs lib/geminabox/server.rb in geminabox-0.13.8

- old
+ new

@@ -1,5 +1,7 @@ +require 'reentrant_flock' + module Geminabox class Server < Sinatra::Base enable :static, :methodoverride use Rack::Session::Pool, :expire_after => 2592000 @@ -63,15 +65,15 @@ return if updated_gemspecs.empty? Geminabox::Indexer.patch_rubygems_update_index_pre_1_8_25(indexer) indexer.update_index updated_gemspecs.each { |gem| dependency_cache.flush_key(gem.name) } rescue Errno::ENOENT - reindex(:force_rebuild) + with_rlock { reindex(:force_rebuild) } rescue => e puts "#{e.class}:#{e.message}" puts e.backtrace.join("\n") - reindex(:force_rebuild) + with_rlock { reindex(:force_rebuild) } end end rescue Gem::SystemExitException end @@ -80,14 +82,28 @@ end def dependency_cache @dependency_cache ||= Geminabox::DiskCache.new(File.join(data, "_cache")) end - end + def with_rlock(&block) + file_class.open(settings.lockfile, File::RDWR | File::CREAT) do |f| + ReentrantFlock.synchronize(f, File::LOCK_EX | File::LOCK_NB, &block) + end + end + # This method provides a test hook, as stubbing File is painful... + def file_class + @file_class ||= File + end + def file_class=(klass) + @file_class = klass + end + end + + before do headers 'X-Powered-By' => "geminabox #{Geminabox::VERSION}" end get '/' do @@ -183,24 +199,16 @@ end private def serialize_update(&block) - with_lock(&block) - rescue AlreadyLocked + with_rlock(&block) + rescue ReentrantFlock::AlreadyLocked halt 503, { 'Retry-After' => settings.retry_interval }, 'Repository lock is held by another process' end - def with_lock - file_class.open(settings.lockfile, File::RDWR | File::CREAT) do |f| - raise AlreadyLocked unless f.flock(File::LOCK_EX | File::LOCK_NB) - yield - end - end - - # This method provides a test hook, as stubbing File is painful... - def file_class - File + def with_rlock(&block) + self.class.with_rlock(&block) end def handle_incoming_gem(gem) begin GemStore.create(gem, params[:overwrite])