Permalink
Browse files

Added retries after receiving HTTPServiceUnavailable.

  • Loading branch information...
1 parent 2314106 commit 214fd266792174960199c919bc88243c44dd5783 @kenpratt committed Apr 2, 2012
Showing with 36 additions and 22 deletions.
  1. +4 −0 History.txt
  2. +27 −13 lib/dbox/api.rb
  3. +1 −3 lib/dbox/db.rb
  4. +4 −6 lib/dbox/syncer.rb
View
@@ -1,3 +1,7 @@
+== 0.6.8 / 2012-04-02
+ * Minor Enhancements
+ * Added retries after receiving HTTPServiceUnavailable from Dropbox API.
+
== 0.6.7 / 2012-03-29
* Minor Enhancements
* Added timeout to SQLite operations to help with threads competing for db operations.
View
@@ -1,4 +1,7 @@
module Dbox
+ NUM_TRIES = 3
+ TIME_BETWEEN_TRIES = 3 # in seconds
+
class ConfigurationError < RuntimeError; end
class ServerError < RuntimeError; end
class RemoteMissing < RuntimeError; end
@@ -62,16 +65,24 @@ def connect
@client = DropboxClient.new(@session, 'dropbox')
end
- def run(path)
+ def run(path, tries = NUM_TRIES, &proc)
begin
- res = yield
+ res = proc.call
handle_response(path, res) { raise RuntimeError, "Unexpected result: #{res.inspect}" }
rescue DropboxNotModified => e
:not_modified
rescue DropboxAuthError => e
raise e
rescue DropboxError => e
- handle_response(path, e.http_response) { raise ServerError, "Server error -- might be a hiccup, please try your request again (#{e.message})" }
+ if e.http_response.kind_of?(Net::HTTPServiceUnavailable) && tries > 0
+ log.info "Encountered 503 on #{path} (likely rate limiting). Sleeping #{TIME_BETWEEN_TRIES}s and trying again."
+ # TODO check for "Retry-After" header and use that for sleep instead of TIME_BETWEEN_TRIES
+ log.debug "Headers: #{e.http_response.to_hash.inspect}"
+ sleep TIME_BETWEEN_TRIES
+ run(path, tries - 1, &proc)
+ else
+ handle_response(path, e.http_response) { raise ServerError, "Server error -- might be a hiccup, please try your request again (#{e.message})" }
+ end
end
end
@@ -95,17 +106,17 @@ def handle_response(path, res, &else_proc)
end
def metadata(path = "/", hash = nil, list=true)
- log.debug "Fetching metadata for #{path}"
run(path) do
+ log.debug "Fetching metadata for #{path}"
res = @client.metadata(path, 10000, list, hash)
log.debug res.inspect
res
end
end
def create_dir(path)
- log.info "Creating #{path}"
run(path) do
+ log.info "Creating #{path}"
begin
@client.file_create_folder(path)
rescue DropboxError => e
@@ -119,17 +130,19 @@ def create_dir(path)
end
def delete_dir(path)
- log.info "Deleting #{path}"
run(path) do
+ log.info "Deleting #{path}"
@client.file_delete(path)
end
end
def get_file(path, file_obj, stream=false)
- log.info "Downloading #{path}"
unless stream
# just download directly using the get_file API
- res = run(path) { @client.get_file(path) }
+ res = run(path) do
+ log.info "Downloading #{path}"
+ @client.get_file(path)
+ end
if res.kind_of?(String)
file_obj << res
true
@@ -142,30 +155,31 @@ def get_file(path, file_obj, stream=false)
res = run(path) { @client.media(path) }
url = res[:url] if res && res.kind_of?(Hash)
if url
+ log.info "Downloading #{path}"
streaming_download(url, file_obj)
else
get_file(path, file_obj, false)
end
end
end
- def put_file(path, file_obj, previous_revision=nil)
- log.info "Uploading #{path}"
+ def put_file(path, local_path, previous_revision=nil)
run(path) do
- @client.put_file(path, file_obj, false, previous_revision)
+ log.info "Uploading #{path}"
+ File.open(local_path, "r") {|f| @client.put_file(path, f, false, previous_revision) }
end
end
def delete_file(path)
- log.info "Deleting #{path}"
run(path) do
+ log.info "Deleting #{path}"
@client.file_delete(path)
end
end
def move(old_path, new_path)
- log.info "Moving #{old_path} to #{new_path}"
run(old_path) do
+ log.info "Moving #{old_path} to #{new_path}"
begin
@client.file_move(old_path, new_path)
rescue DropboxError => e
View
@@ -517,9 +517,7 @@ def download
end
def upload
- File.open(local_path) do |f|
- api.put_file(remote_path, f)
- end
+ api.put_file(remote_path, local_path)
force_metadata_update_from_server
end
end
View
@@ -620,12 +620,10 @@ def delete_file(file)
def upload_file(file)
local_path = relative_to_local_path(file[:path])
remote_path = relative_to_remote_path(file[:path])
- File.open(local_path) do |f|
- db_entry = database.find_by_path(file[:path])
- last_revision = db_entry ? db_entry[:revision] : nil
- res = api.put_file(remote_path, f, last_revision)
- process_basic_remote_props(res)
- end
+ db_entry = database.find_by_path(file[:path])
+ last_revision = db_entry ? db_entry[:revision] : nil
+ res = api.put_file(remote_path, local_path, last_revision)
+ process_basic_remote_props(res)
end
def force_metadata_update_from_server(entry)

0 comments on commit 214fd26

Please sign in to comment.