Skip to content

Commit b30982f

Browse files
Add retries to editor builds (#507)
closes #506 --------- Co-authored-by: create-issue-branch[bot] <53036503+create-issue-branch[bot]@users.noreply.github.com> Co-authored-by: Dan Halson <[email protected]>
1 parent 01378de commit b30982f

File tree

3 files changed

+64
-45
lines changed

3 files changed

+64
-45
lines changed

app/jobs/create_students_job.rb

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,25 @@
33
class ConcurrencyExceededForSchool < StandardError; end
44

55
class CreateStudentsJob < ApplicationJob
6+
retry_on StandardError, wait: :polynomially_longer, attempts: 3 do |_job, e|
7+
Sentry.capture_exception(e)
8+
raise e
9+
end
10+
11+
# Don't retry...
12+
rescue_from ConcurrencyExceededForSchool do |e|
13+
Rails.logger.error "Only one job per school can be enqueued at a time: #{school_id}"
14+
Sentry.capture_exception(e)
15+
raise e
16+
end
17+
18+
# Don't retry...
19+
rescue_from ActiveRecord::RecordInvalid do |e|
20+
Rails.logger.error "Failed to create student role: #{e.record.errors.full_messages.join(', ')}"
21+
Sentry.capture_exception(e)
22+
raise e
23+
end
24+
625
include GoodJob::ActiveJobExtensions::Concurrency
726

827
queue_as :default
@@ -36,23 +55,4 @@ def perform(school_id:, students:, token:)
3655
Role.student.create!(school_id:, user_id:)
3756
end
3857
end
39-
40-
# Don't retry...
41-
rescue_from ConcurrencyExceededForSchool do |e|
42-
Rails.logger.error "Only one job per school can be enqueued at a time: #{school_id}"
43-
Sentry.capture_exception(e)
44-
raise e
45-
end
46-
47-
# Don't retry...
48-
rescue_from ActiveRecord::RecordInvalid do |e|
49-
Rails.logger.error "Failed to create student role: #{e.record.errors.full_messages.join(', ')}"
50-
Sentry.capture_exception(e)
51-
raise e
52-
end
53-
54-
retry_on StandardError, attempts: 3 do |_job, e|
55-
Sentry.capture_exception(e)
56-
raise e
57-
end
5858
end

app/jobs/upload_job.rb

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,21 @@
33
require 'open-uri'
44
require 'github_api'
55

6+
class InvalidDirectoryStructureError < StandardError; end
7+
class RepositoryNotFoundError < StandardError; end
8+
69
class UploadJob < ApplicationJob
10+
retry_on StandardError, wait: :polynomially_longer, attempts: 3 do |_job, e|
11+
Sentry.capture_exception(e)
12+
raise e
13+
end
14+
15+
# Don't retry...
16+
rescue_from RepositoryNotFoundError, InvalidDirectoryStructureError do |e|
17+
Sentry.capture_exception(e)
18+
raise e
19+
end
20+
721
@skip_job = false
822

923
ProjectContentQuery = GithubApi::Client.parse <<-GRAPHQL
@@ -40,6 +54,7 @@ class UploadJob < ApplicationJob
4054
def perform(payload)
4155
modified_locales(payload).each do |locale|
4256
projects_data = load_projects_data(locale, repository(payload), owner(payload))
57+
raise RepositoryNotFoundError, "Repository not found: #{repository(payload)}" if projects_data.data&.repository&.object.nil?
4358

4459
projects_data.data.repository.object.entries.each do |project_dir|
4560
project = format_project(project_dir, locale, repository(payload), owner(payload))
@@ -51,9 +66,6 @@ def perform(payload)
5166
project_importer = ProjectImporter.new(**project)
5267
project_importer.import!
5368
end
54-
rescue StandardError => e
55-
Sentry.capture_exception(e)
56-
raise e # Re-raise the error to make the job fail
5769
end
5870
end
5971

@@ -159,5 +171,3 @@ def file_mime_type(file)
159171
Marcel::MimeType.for(file.object, name: file.name)
160172
end
161173
end
162-
163-
class InvalidDirectoryStructureError < StandardError; end

spec/jobs/upload_job_spec.rb

Lines changed: 30 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
require 'rails_helper'
44

55
RSpec.describe UploadJob do
6+
include ActiveJob::TestHelper
7+
68
around do |example|
79
ClimateControl.modify GITHUB_AUTH_TOKEN: 'secret', GITHUB_WEBHOOK_REF: 'branches/whatever' do
810
example.run
@@ -122,18 +124,16 @@
122124
}
123125
end
124126

125-
before do
126-
stub_request(:get, 'https://github.com/me/my-amazing-repo/raw/branches/whatever/ja-JP/code/dont-collide-starter/astronaut1.png').to_return(status: 200, body: '', headers: {})
127-
stub_request(:get, 'https://github.com/me/my-amazing-repo/raw/branches/whatever/ja-JP/code/dont-collide-starter/music.mp3').to_return(status: 200, body: '', headers: {})
128-
stub_request(:get, 'https://github.com/me/my-amazing-repo/raw/branches/whatever/ja-JP/code/dont-collide-starter/video.mp4').to_return(status: 200, body: '', headers: {})
129-
end
130-
131127
context 'with the build flag undefined' do
132128
let(:raw_response) { modifiable_response }
133129

134130
before do
135131
allow(GithubApi::Client).to receive(:query).and_return(graphql_response)
136132
allow(ProjectImporter).to receive(:new).and_call_original
133+
134+
stub_request(:get, 'https://github.com/me/my-amazing-repo/raw/branches/whatever/ja-JP/code/dont-collide-starter/astronaut1.png').to_return(status: 200, body: '', headers: {})
135+
stub_request(:get, 'https://github.com/me/my-amazing-repo/raw/branches/whatever/ja-JP/code/dont-collide-starter/music.mp3').to_return(status: 200, body: '', headers: {})
136+
stub_request(:get, 'https://github.com/me/my-amazing-repo/raw/branches/whatever/ja-JP/code/dont-collide-starter/video.mp4').to_return(status: 200, body: '', headers: {})
137137
end
138138

139139
it 'enqueues the job' do
@@ -188,6 +188,10 @@
188188
let(:raw_response) { modifiable_response.deep_dup }
189189

190190
before do
191+
stub_request(:get, 'https://github.com/me/my-amazing-repo/raw/branches/whatever/ja-JP/code/dont-collide-starter/astronaut1.png').to_return(status: 200, body: '', headers: {})
192+
stub_request(:get, 'https://github.com/me/my-amazing-repo/raw/branches/whatever/ja-JP/code/dont-collide-starter/music.mp3').to_return(status: 200, body: '', headers: {})
193+
stub_request(:get, 'https://github.com/me/my-amazing-repo/raw/branches/whatever/ja-JP/code/dont-collide-starter/video.mp4').to_return(status: 200, body: '', headers: {})
194+
191195
project_dir_entry = raw_response['data']['repository']['object']['entries'].find do |entry|
192196
entry['name'] == 'dont-collide-starter'
193197
end
@@ -207,26 +211,31 @@
207211
end
208212
end
209213

210-
context 'with a graphql error response' do
211-
let(:raw_response) do
212-
{
213-
errors: [
214-
{
215-
'message' => 'Simulated INTERNAL_SERVER_ERROR message',
216-
'locations' => [{ 'line' => 2, 'column' => 4 }],
217-
'path' => %w[query repository object],
218-
'extensions' => { 'code' => 'INTERNAL_SERVER_ERROR' }
219-
}
220-
]
221-
}
214+
context 'when repository is not found' do
215+
let(:graphql_response) do
216+
GraphQL::Client::Response.new(
217+
{
218+
'errors' => [
219+
{
220+
'message' => 'Simulated NOT_FOUND error message',
221+
'locations' => [{ 'line' => 2, 'column' => 4 }],
222+
'path' => %w[query repository],
223+
'extensions' => { 'code' => 'NOT_FOUND' }
224+
}
225+
]
226+
},
227+
data: nil
228+
)
222229
end
223230

224231
before do
225-
stub_request(:post, 'https://api.github.com/graphql').to_return(status: 200, body: raw_response.to_json, headers: {})
232+
allow(GithubApi::Client).to receive(:query).and_return(graphql_response)
226233
end
227234

228-
it 'raises a GraphQL::Client::Error' do
229-
expect { described_class.perform_now(payload) }.to raise_error(GraphQL::Client::Error, /Simulated INTERNAL_SERVER_ERROR message/)
235+
it 'raises RepositoryNotFoundError' do
236+
expect do
237+
described_class.perform_now(payload)
238+
end.to raise_error(RepositoryNotFoundError, 'Repository not found: my-amazing-repo')
230239
end
231240
end
232241
end

0 commit comments

Comments
 (0)