Skip to content

Commit c1dc110

Browse files
committed
[hotfix] updated retries on rate limit upload errors
1 parent a4170bf commit c1dc110

File tree

3 files changed

+42
-6
lines changed

3 files changed

+42
-6
lines changed

app/controllers/lcms/engine/admin/curriculums_controller.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ def children
1717
Array.wrap(Lcms::Engine::Resource.tree.find(id)&.children)
1818
end
1919

20-
render json: resources.map { |res| CurriculumPresenter.new.parse_jstree_node(res) }
20+
render json: resources.tree.map { |res| CurriculumPresenter.new.parse_jstree_node(res) }
2121
end
2222

2323
def update

docs/env-variables.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,11 @@ The project uses several Google products, including analytics, OAuth for allowin
5555
| GOOGLE_APPLICATION_TEMPLATE_PORTRAIT | Id of the Google document which is a template for portrait materials(can be identified the same way as `GOOGLE_APPLICATION_FOLDER_ID `) |
5656
| GOOGLE_APPLICATION_TEMPLATE_LANDSCAPE | Id of the Google document which is a template for landscape materials(can be identified the same way as `GOOGLE_APPLICATION_FOLDER_ID `) |
5757
| GOOGLE_APPLICATION_PREVIEW_FOLDER_ID | Folder ID where preview documents should get placed |
58-
| GOOGLE_API_CLIENT_UPLOAD_RETRIES || |
59-
| GOOGLE_API_CLIENT_UPLOAD_TIMEOUT || |
58+
| GOOGLE_API_CLIENT_UPLOAD_RETRIES | Number of retries on upload, default is 5 | |
59+
| GOOGLE_API_CLIENT_UPLOAD_TIMEOUT | Upload timeout, default is 60 seconds | |
60+
| GOOGLE_API_CLIENT_UPLOAD_RATE_BASE_INTERVAL | Initial interval in seconds between tries for rate limit errors on upload, default is 2| |
61+
| GOOGLE_API_CLIENT_UPLOAD_RATE_MAX_INTERVAL | The maximum interval in seconds that any individual retry can reach, default is 300 | |
62+
| GOOGLE_API_CLIENT_UPLOAD_RATE_MAX_ELAPSED_TIME | The maximum amount of total time in seconds that code is allowed to keep being retried, default 900 (15 min)| |
6063

6164
### Miscellaneous settings
6265
| Name | Description |

lib/document_exporter/gdoc/base.rb

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@ class Base < DocumentExporter::Base
1212
options: {
1313
open_timeout_sec: GOOGLE_API_CLIENT_UPLOAD_TIMEOUT,
1414
read_timeout_sec: GOOGLE_API_CLIENT_UPLOAD_TIMEOUT,
15-
retries: GOOGLE_API_CLIENT_UPLOAD_RETRIES,
1615
send_timeout_sec: GOOGLE_API_CLIENT_UPLOAD_TIMEOUT
1716
}
1817
}.freeze
18+
GOOGLE_API_RATE_RETRIABLE_ERRORS = [Google::Apis::ServerError, Google::Apis::RateLimitError].freeze
1919
VERSION_RE = /_v\d+$/i.freeze
2020

2121
attr_reader :document, :options
@@ -52,7 +52,18 @@ def export
5252
upload_source: StringIO.new(content)
5353
}.merge(GOOGLE_API_UPLOAD_OPTIONS)
5454

55-
@id = Retriable.retriable(base_interval: 1, tries: GOOGLE_API_CLIENT_UPLOAD_RETRIES) do
55+
# use general API settings for inner API call and wrap it with additional retry logic
56+
@id = Retriable.retriable(base_interval: ENV.fetch('GOOGLE_API_CLIENT_UPLOAD_RATE_BASE_INTERVAL', 5).to_i,
57+
multiplier: ENV.fetch(
58+
'GOOGLE_API_CLIENT_UPLOAD_RATE_MULTIPLIER', 2
59+
).to_f,
60+
max_interval: ENV.fetch(
61+
'GOOGLE_API_CLIENT_UPLOAD_RATE_MAX_INTERVAL', 300
62+
).to_i,
63+
max_elapsed_time: ENV.fetch('GOOGLE_API_CLIENT_UPLOAD_RATE_MAX_ELAPSED_TIME',
64+
900).to_i,
65+
on_retry: log_retries(file_id, metadata),
66+
tries: GOOGLE_API_CLIENT_UPLOAD_RETRIES) do
5667
if file_id.present?
5768
drive_service.service.update_file(file_id, metadata, params)
5869
else
@@ -81,7 +92,17 @@ def export_to(folder_id, file_id: nil)
8192
upload_source: StringIO.new(content)
8293
}.merge(GOOGLE_API_UPLOAD_OPTIONS)
8394

84-
@id = Retriable.retriable(base_interval: 1, tries: GOOGLE_API_CLIENT_UPLOAD_RETRIES) do
95+
@id = Retriable.retriable(base_interval: ENV.fetch('GOOGLE_API_CLIENT_UPLOAD_RATE_BASE_INTERVAL', 5).to_i,
96+
multiplier: ENV.fetch(
97+
'GOOGLE_API_CLIENT_UPLOAD_RATE_MULTIPLIER', 2
98+
).to_f,
99+
max_interval: ENV.fetch(
100+
'GOOGLE_API_CLIENT_UPLOAD_RATE_MAX_INTERVAL', 300
101+
).to_i,
102+
max_elapsed_time: ENV.fetch('GOOGLE_API_CLIENT_UPLOAD_RATE_MAX_ELAPSED_TIME',
103+
900).to_i,
104+
on_retry: log_retries(file_id, metadata),
105+
tries: GOOGLE_API_CLIENT_UPLOAD_RETRIES) do
85106
if file_id.present?
86107
drive_service.service.update_file(file_id, metadata, params)
87108
else
@@ -140,6 +161,18 @@ def gdoc_folder_tmp(material_ids)
140161
self
141162
end
142163

164+
def log_retries(file_id, metadata)
165+
proc do |exception, try, elapsed_time, next_interval|
166+
msg = "#{exception.class}: '#{exception.message}' - #{try} tries in #{elapsed_time} seconds " \
167+
"and #{next_interval} seconds until the next try. " \
168+
"File ID: #{file_id}, Metadata: #{metadata.inspect}"
169+
Rails.logger.error(msg)
170+
if defined?(Airbrake) && ENV.fetch('AIRBRAKE_UPLOAD_ERRORS_NOTIFY', 'off') == 'on'
171+
::Airbrake.notify_sync(Airbrake.build_notice(msg))
172+
end
173+
end
174+
end
175+
143176
def post_processing
144177
Retriable.retriable(base_interval: 5, tries: 10) do
145178
Lcms::Engine::Google::ScriptService.new(document).execute(@id)

0 commit comments

Comments
 (0)