-
Notifications
You must be signed in to change notification settings - Fork 769
Fix concurrency issues with GHIssue addLabels() and removeLabels() by using labels endpoint
#1054
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix concurrency issues with GHIssue addLabels() and removeLabels() by using labels endpoint
#1054
Conversation
|
@bitwiseman I created this PR first as we have detected some issues with bridge methods and Mockito (we are mocking the API calls in our GH App framework) so I prefer to deal with the return values in another PR and check that things are OK for us in a second phase. This fix is more urgent as our bot is removing labels that we just added due to this concurrency issue. Thanks! |
d734663 to
c742050
Compare
bitwiseman
left a comment
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.
One test change requested. Otherwise, look good to me.
| newLabels.add(l.getName()); | ||
| } | ||
| for (String name : names) { | ||
| root.createRequest().method("DELETE").withUrlPath(getIssuesApiRoute() + "/labels", name).send(); |
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.
Ouch. I didn't notice this behavior. Not great for rate limit budget... But it is correct. Good job.
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.
Yeah, I agree it's unfortunate they did it that way. It should have been symmetrical with adding labels IMHO.
| } | ||
| setLabels(newLabels.toArray(new String[0])); | ||
| root.createRequest() | ||
| .with("labels", names.toArray(new String[0])) |
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.
Wait... this should add a list of labels in one call, not only work for one label.
https://docs.github.com/en/rest/reference/issues#add-labels-to-an-issue
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 think that's what it did anyway but I see you can pass directly the collection so that's what is done now.
c742050 to
6da5144
Compare
|
@bitwiseman I think I addressed all your concerns and I checked adding two labels only makes one API call. |
6da5144 to
1fefc77
Compare
| labels = getRepository().getPullRequest(p.getNumber()).getLabels(); | ||
| assertEquals(1, labels.size()); | ||
| assertEquals(label1, labels.iterator().next().getName()); | ||
| } |
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.
Hm, if you add the following above this line, you'll get a GHFileNotFoundException.
p.removeLabels(label2);
Need to test this scenario. Also, it seems like this could still result in concurrency issues. Two clients go to remove the same label and one gets an error while the other doesn't. Would you rather merge this change with this or work on a solution?
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 you... what? There's a word missing :)
I don't see how the case you're talking about is a concurrency issue? For sure, if you have several clients removing the same labels at the same time, you will have errors. But that's how the APIs are designed and that's expected in my opinion.
What's not acceptable is the issue that this PR fixes e.g. your use of the API is perfectly fine and you lose 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.
(Edited my previous message).
I'm not saying the you have not properly fixed the issue in question. I'm just raising your awareness that you may still run into unexpected errors but only when removing labels.
When you call addLabels() and a label is already present, GitHub returns no error. Multiple clients can add the same label and none will error.
When you call removeLabels() and a label is not present you get an error. Multiple clients cannot remove the same label without all but one of them erroring. The behavior is reasonable but asymmetric. Also, we're providing a single method call to wrap multiple API calls. If adding failed for some reason, no labels will be added. If removeLabels() fails, some label will be removed and others will not. Also, the old method would not throw if you removed a label that was not present.
What you've written simply passes the errors returned from GitHub to the user. Good and fine, but it is a more significant change not just a fix to incorrect behavior.
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.
We probably want to have removeLabels(...) match the old method behavior and not throw if any of the label s in the list are not present.
And then add a removeLabel(String) that does throw if the specified label isn't present.
bitwiseman
left a comment
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.
Sorry, a few more changes and questionsI didn't think of on the previous round.
bitwiseman
left a comment
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.
@gsmet
I updated removeLabels() to match the existing non-throwing behavior and added a removeLabel() that will behave like the GitHub API and throw.
This retains your fixes but also stays consistent with past behavior where possible.
What do you think?
|
@bitwiseman sorry, I was extremely busy this week. I'll try to have a look next week! |
|
@bitwiseman I find it a bit weird that So I think we should merge it! |
addLabels() and removeLabels() by using labels endpoint
Description
Fixes concurrency issues when adding and removing labels by using the proper GitHub APIs.
Fixes #1049
Before submitting a PR:
We love getting PRs, but we hate asking people for the same basic changes every time.
master. Create your PR from that branch.mvn -D enable-ci clean install sitelocally. If this command doesn't succeed, your change will not pass CI.When creating a PR: