-
Notifications
You must be signed in to change notification settings - Fork 566
Conversation
Fix assumption that all assignments need to push starter code
if import_resiliency_enabled? | ||
job_started = false | ||
if current_invitation.accepted? || current_invitation.errored? | ||
AssignmentRepo::CreateGitHubRepositoryJob.perform_later(current_assignment, current_user) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we ensure that the job is a unique job before we kick it off? Since jobs retry with exponential backoff we could end up in a situation where another job is kicked off while another is about to be retired.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If possible, yes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By default Sidekiq doesn't have this feature. It does in enterprise, but we aren't on that licensed plan.
Another option would be to use mhenrixon/sidekiq-unique-jobs. This would require us to move away from ActiveJob and to using straight Sidekiq.
Possibly worth investigating in a follow up PR.
RepositoryCreationStatusChannel.channel(user_id: user.id), | ||
text: Creator::REPOSITORY_CREATION_COMPLETE, | ||
status: assignment.invitation&.status | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we be recording stats about successful repo creation on this vs the old way? if so using GitHubClassroom.statsd
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Definitely, we should be recording metrics wherever we think might help us be confident the new porter logic is better and more successful than the old one. I said this in an earlier comment, but we'll also want to have granular metrics so we can distinguish imports made using old logic and new logic.
- [deadline, 3] | ||
- [boom, 3] | ||
- [create_repository, 3] | ||
- [porter_status, 3] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Worth mentioning that this many custom queues could be inefficient (#1381 )
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I left some comments, mostly everything looks 👍, I think the biggest thing I was unsure about was this new create
action. I left some inline comments, let me know what you think.
app/assets/javascripts/setupv2.js
Outdated
$.ajax({type: "GET", url: path}).done(function(data) { | ||
|
||
display_progress(data); | ||
setTimeout(check_progress, 3000); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The JS here looks good 👍
The only thing I'd suggest is abstracting the two uses of 3000
out to a constant at the top of the file so that if we want to adjust the polling rate in the future, we don't need to go through the whole file looking for where it is.
app/assets/javascripts/setupv2.js
Outdated
const path = progress_path(); | ||
|
||
$.ajax({type: "GET", url: path}).done(function(data) { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style nit, do we need a newline here?
app/assets/javascripts/setupv2.js
Outdated
|
||
start_job = function() { | ||
const path = job_path(); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same style nit here
result = current_invitation.redeem_for(current_user, import_resiliency: import_resiliency_enabled?) | ||
case result.status | ||
when :success | ||
GitHubClassroom.statsd.increment("exercise_invitation.accept") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of re-using the old metric key here, what do you think about using a new one? v2_excercise_invitation.accept
, for example.
This'll give us a little bit more granularity in our metrics when trying to see how the new flow is performing.
GitHubClassroom.statsd.increment("exercise_invitation.accept") | ||
redirect_to setupv2_assignment_invitation_path | ||
when :error | ||
GitHubClassroom.statsd.increment("exercise_invitation.fail") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment about metric granularity here
if import_resiliency_enabled? | ||
job_started = false | ||
if current_invitation.accepted? || current_invitation.errored? | ||
AssignmentRepo::CreateGitHubRepositoryJob.perform_later(current_assignment, current_user) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If possible, yes.
@@ -19,32 +19,25 @@ class CreateGitHubRepositoryJob < ApplicationJob | |||
def perform(assignment, user) | |||
start = Time.zone.now | |||
|
|||
assignment.invitation&.creating_repo! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where is this method defined? I wasn't able to find it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah it's an enum helper, nevermind!
RepositoryCreationStatusChannel.channel(user_id: user.id), | ||
text: Creator::REPOSITORY_CREATION_COMPLETE, | ||
status: assignment.invitation&.status | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Definitely, we should be recording metrics wherever we think might help us be confident the new porter logic is better and more successful than the old one. I said this in an earlier comment, but we'll also want to have granular metrics so we can distinguish imports made using old logic and new logic.
# | ||
# rubocop:disable MethodLength | ||
# rubocop:disable AbcSize | ||
def redeem_for(invitee, import_resiliency: false) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of using a kwarg here, can we just directly check the feature flag?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't use the feature dependency here because we are outside of a controller (feature 🚩s are defined on ApplicationController
).
@@ -0,0 +1,5 @@ | |||
class AddStatusToAssignmentInvitation < ActiveRecord::Migration[5.1] | |||
def change | |||
add_column :assignment_invitations, :status, :integer |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The migration will need to be split into it's own PR, would you mind doing that and pinging me on it? The diff should be this file + the schema diff and nothing else.
Also one other thing I'd suggest, this PR is pretty big and it's hard to review and be sure it's 100% correct. If it's possible in the future, I'd recommend breaking PRs into more atomic, smaller changes 😅 |
.and_return(result) | ||
|
||
patch :accept, params: { id: invitation.key } | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Layout/BlockAlignment: end at 143, 4 is not aligned with it "sends an event to statsd" do at 135, 6.
Update
Things to do in followup PRs
Can I get some final 👀 on this? @d12 |
What
This PR creates a new user flow that utilizes the new import resiliency changes made in #1368 and #1378 for the purpose of solving #1253.
This particular PR proposes a couple of significant additions:
CreateGitHubRepositoryJob
's andPorterStatusJob
's queues with sidekiqstatus
column toAssignmentInvitation
import_resiliency
feature 🚩AssignmentInvitationController
:GET #progress
- JSON api that returns the status of an invitationPOST #create_repo
- if the invitation isaccepted
, kicks off aCreateGitHubRepositoryJob
GET #setupv2
- renders a live updating view of the repo creation progressAll of the new repo creation flow is hiding behind the
import_resiliency
feature 🚩ActionCable
All the server work for ActionCable is done. The client side work will require some extra thought so I have left that work for a follow up PR since this is already an 🐘. Instead of ActionCable we are using short polling and hitting a
GET #progress
for now.What if it errors?
Right now if it errors the UI will reflect the error state but I am yet to add retry button. There is a route ready for the retry button but I have a question about unique/locking background jobs.
What does it look like?