Skip to content
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

JENKINS-48820# Fix for stack overflow in flownode sse event generation #1667

Merged
merged 4 commits into from Feb 21, 2018

Conversation

vivek
Copy link
Collaborator

@vivek vivek commented Feb 20, 2018

Description

Fix for stack overflow error during pipeline execution SSE event generation, has other minor improvements.

See JENKINS-48820.

Submitter checklist

  • Link to JIRA ticket in description, if appropriate.
  • Change is code complete and matches issue description
  • Appropriate unit or acceptance tests or explanation to why this change has no tests
  • Reviewer's manual test instructions provided in PR description. See Reviewer's first task below.

Reviewer checklist

  • Run the changes and verified the change matches the issue description
  • Reviewed the code
  • Verified that the appropriate tests have been written or valid explanation given

@vivek
Copy link
Collaborator Author

vivek commented Feb 20, 2018

@svanoort I think I am picking up right API to get immediate parent node. PTAL.

@@ -203,6 +204,9 @@ public void setBlockErrorAction(ErrorAction blockErrorAction) {
* Filters by class to mimic Item.getActions(class).
*/
public <T extends Action> Collection<T> getPipelineActions(Class<T> clazz) {
if(pipelineActions == null){
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixes NPE happening in cases where there are no actions added.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cheers!

@vivek vivek force-pushed the bug/JENKINS-48820-stack-overflow branch from 6910306 to e7e49af Compare February 20, 2018 21:23
Copy link
Member

@svanoort svanoort left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not 100% sure where this fits in the bigger picture (there may be a way to simplify overall) but I think much of this can be done with just a single API call using the new APIs.

}

private String toPath(List<String> branch) {
private String toPath(Iterator<String> branch) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🐜 Seems like we could just pass an Iterable rather than a one-shot iterator?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or a collection.

@@ -164,7 +149,7 @@ private static Message newMessage(PipelineEventChannel.Event event, FlowExecutio
return message;
}

private Message newMessage(PipelineEventChannel.Event event, FlowNode flowNode, List<String> branch) {
private Message newMessage(PipelineEventChannel.Event event, FlowNode flowNode, Iterator<String> branch) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🐜 Again, perhaps we can do an Iterable or collection rather than an Iterator?

if (parent instanceof StepStartNode) {
if (parent.getAction(BodyInvocationAction.class) != null) {
return parent;
while (parentBlockId != null) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think what you want is myFlowNode.getEnclosingBlocks() which returns a list of blocks -- perhaps combined with Guava or Java 8 stream/filter APIs, perhaps via new NodeStepTypePredicate('parallel')) or FlowScanningUtils.hasActionPredicate(SomeAction.class)) -- it'll do all these goodies for you.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@svanoort I looked at myFlowNode.getEnclosingBlocks(), it doesn't return blocks in order. This code was not written to me and I want to keep changes to minimum as it might break UI. Previous code was making sure preserving certain order, so I would prefer leaving the code with fixing SOF problem with minor enhancements.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vivek Could we just do a Lists.reverse, to maintain the order? It's iterating in inside-out order here so I think you want to simply invert that.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@svanoort Right. I was not planning to use was due to this javadoc of GraphLookupView.findAllEnclosingBlockStarts() , https://github.com/jenkinsci/workflow-api-plugin/blob/a20f21fddc6831f51c3ceeefd3ed1b744b899e98/src/main/java/org/jenkinsci/plugins/workflow/graph/GraphLookupView.java#L55 that says order is not guaranteed. After clarification offline with you, I am fine using it. Please open a PR to fix the Javadoc to make it clear that inside-out order will be maintained.

@sophistifunk
Copy link
Collaborator

Was this SO due to an infinite loop, or just by a complicated pipeline?

@vivek
Copy link
Collaborator Author

vivek commented Feb 20, 2018

@sophistifunk caused by large number of steps in pipelines about 4600+ as reported in https://issues.jenkins-ci.org/browse/JENKINS-48820.

@vivek
Copy link
Collaborator Author

vivek commented Feb 21, 2018

@svanoort PTAL

return null;
/* package: so that we can unit test it */ List<String> getBranch(FlowNode flowNode) {
return Lists.reverse(flowNode.getEnclosingBlocks().stream()
.map(FlowNode::getId).collect(Collectors.toList()));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh hey, if you just wanted the IDs there's node.getAllEnclosingIds()

Please don't kill me :) I've got APIs to do pretty much all the things you'd want to do with FlowNodes at this point...

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ha ha. This is great. Let me make this change.

StringBuilder builder = new StringBuilder();
for (String leaf : branch) {
for(String leaf: branch){
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🐜 Can this path creation with just branch.stream().collect(Collectors.joining("/")) if you're feeling all Streams-y :)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, there are many places in the code we need to change to adopt java 8, keeping the scope limited to just this fix, so be making such changes some other time.

Copy link
Member

@svanoort svanoort left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's close enough -- can be tuned by use of Java 8 features and an API that gives you things in the same format but ::shrug::

@vivek vivek merged commit cef8aad into master Feb 21, 2018
@vivek vivek deleted the bug/JENKINS-48820-stack-overflow branch February 21, 2018 21:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
3 participants