2009-08-04 25 views
8

スレッドFTP接続を使用して複数のFTPダウンロードを高速化しようとしました。私の問題は、私は常にスレッドがハングすることです。私は、ftpのトランザクションを再試行する必要があることをFTPに伝えるか、少なくともFTP接続が掛かっているかを知るためのきれいな方法を探しています。Ruby Net :: FTPタイムアウトスレッド

以下のコードでは、各スレッドにダウンロード予定のファイルの一覧がある5/6の別個のFTP接続をスレッドしています。スクリプトが完了すると、いくつかのスレッドがハングアップして結合できなくなります。最後の成功したダウンロード時間を表すために変数@last_updatedを使用しています。現在の時刻+20秒が@last_updatedを超えている場合は、残りのスレッドを強制終了します。より良い方法がありますか?

threads = [] 
max_thread_pool = 5 
running_threads = 0 
Thread.abort_on_exception = true 

existing_file_count = 0 
files_downloaded = 0 

errors = [] 
missing_on_the_server = [] 
@last_updated = Time.now 

if ids.length > 0 
    ids.each_slice(ids.length/max_thread_pool) do |id_set| 
     threads << Thread.new(id_set) do |t_id_set| 
      running_threads += 1 
      thread_num = running_threads 
      thread_num.freeze 
      puts "making thread # #{thread_num}" 
      begin 
       ftp = Net::FTP.open(@remote_site) 
       ftp.login(@remote_user, @remote_password) 
       ftp.binary = true 
       #ftp.debug_mode = true 
       ftp.passive = false 
      rescue 
       raise "Could not establish FTP connection" 
      end 
      t_id_set.each do |id| 
       @last_updated = Time.now 
       rmls_path = "/_Photos/0#{id[0,2]}00000/#{id[2,1]}0000/#{id[3,1]}000/#{id}-1.jpg" 
       local_path = "#{@photos_path}/01/#{id}-1.jpg" 
       progress += 1 
       unless File.exist?(local_path) 
        begin 
         ftp.getbinaryfile(rmls_path, local_path) 
         puts "ftp reponse: #{ftp.last_response}" 
         # find the percentage of progress just for fun 
         files_downloaded += 1 
         p = sprintf("%.2f", ((progress.to_f/total) * 100)) 
         puts "Thread # #{thread_num} > %#{p} > #{progress}/#{total} > Got file: #{local_path}" 
        rescue 
         errors << "#{thread_num} unable to get file > ftp response: #{ftp.last_response}" 
         puts errors.last 
         if ftp.last_response_code.to_i == 550 
          # Add the missing file to the missing list 
          missing_on_the_server << errors.last.match(/\d{5,}-\d{1,2}\.jpg/)[0] 
         end 
        end 
       else 
        puts "found file: #{local_path}" 
        existing_file_count += 1 
       end 
      end 
      puts "closing FTP connection #{thread_num}" 
      ftp.close 
     end # close thread 
    end 
end 

# If @last_updated has not been updated on the server in over 20 seconds, wait 3 seconds and check again 
while Time.now < @last_updated + 20 do 
    sleep 3 
end 
# threads are hanging so joining the threads does not work. 
threads.each { |t| t.kill } 

答えて

9

働いていた私のためのトリックは、FTP接続がぶら下がっていなかったことを確認するためにルビーのTimeout.timeoutを使用することでした。

begin 
    Timeout.timeout(10) do 
     ftp.getbinaryfile(rmls_path, local_path) 
    end 
    # ... 
rescue Timeout::Error 
    errors << "#{thread_num}> File download timed out for: #{rmls_path}" 
    puts errors.last 
rescue 
    errors << "unable to get file > ftp reponse: #{ftp.last_response}" 
    # ... 
end 

ハングするFTPダウンロードによって、スレッドがハングアップしているように見えました。むしろ醜いより

threads.each { |t| j.join } 

:今すぐスレッドがもはやぶら下がっていることを、私はスレッドを扱うより適切な方法を使用することができます

# If @last_updated has not been updated on the server in over 20 seconds, wait 3 seconds and check again 
while Time.now < @last_updated + 20 do 
    sleep 3 
end 
# threads are hanging so joining the threads does not work. 
threads.each { |t| t.kill } 
関連する問題