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

Lock multiple resources using labels and quantities within the Pipeline lock step #26

Closed
wants to merge 15 commits into from
Closed

Conversation

Aeon512
Copy link
Contributor

@Aeon512 Aeon512 commented Apr 23, 2016

As a result of JENKINS-34268 and JENKINS-34273 I tried to extend the current Pipeline lock step implementation with an additional optional argument label: "LabelName" to specify that resources assigned to this label shall be requested as well as an additional optional argument quantity: 3 to request 3 such resources. (If left out, quantity defaults to 1.)

The locking and unlocking mechanisms had to be largely modified in order to deal with several resources in parallel (the current pipeline implementation can only handle a single resource within one step). One major modification was to move the list of queued context out of the actual LockableResource (since we are now dealing with several resources at once) and move this queue to the LockableResourcesManager instead.

Example Usage:

lock(label: "MyLabel", quantity: 2) {
    // body
}

Since this is my first Jenkins Plugin contribution (and the first time writing actual Java code) I'm open for any sorts of feedback, review comments or similar. The same holds actually for GitHub, so if there is anything I can improve doing forks, commits and pull requests, please let me know :)

As of today, 2016-04-22, this fork is up-to-date with the base repository, all unit-tests can be executed, and additional unit-tests for the newly added functionality (labels & quantities) have been added. The plugin worked also fine in my manual Jenkins tests.

}

@DataBoundSetter
public void setInversePrecedence(boolean inversePrecedence) {
this.inversePrecedence = inversePrecedence;
}

@DataBoundSetter
public void setResource(@Nullable String resource) {
Copy link
Member

Choose a reason for hiding this comment

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

More clear if you add @CheckForNull in the field rather that using @Nullable here.

@amuniz
Copy link
Member

amuniz commented Apr 25, 2016

After a quick review (as it would need a deeper one), it seems that the static state is not persisted now (queued step contexts). Why the restart tests are passing? I don't know, probably something to fix in tests.

@Aeon512
Copy link
Contributor Author

Aeon512 commented Apr 25, 2016

@amuniz Thanks for the quick review. I have addressed most of your points except the still open issue regarding queued step contexts. Your comment regarding static state is beyond my understanding.

As mentioned in the comment above, I think the queued step context is correctly stored by issuing the save() call. The problem with storing the queued step contexts in individual resources is mostly, that by using labels you don't know apriori which resource will be finally used within the lock as their availability might change. Hence, you would have to store the queue within all possible resource and maintain these different lists which yield to a quite complicated solution imho.

Any ideas how to progress forward here?

@amuniz
Copy link
Member

amuniz commented Apr 25, 2016

@Aeon512 I need to spend some time doing a deeper review. But at least, you will need to add a migration process to keep backward compatibility with previous installations. That migration would need to move all waiting contexts in the old structure to the new one. For that purpose the old field LockableResources#queuedContexts needs to be kept (not removed but @Deprecated). The migration process can be implemented by using @InitMilestone. Perhaps you can find some similar example here.

@Aeon512
Copy link
Contributor Author

Aeon512 commented Apr 25, 2016

@amuniz Thanks a lot for your work so far. I would really appreciate if you could take the time for doing a deeper review.

I have restored the old field LockableResource#queuedContexts as well as a new getter to obtain its data LockableResource#getQueuedContexts. Reharding the migration process I have tried to implement some code within BackwardCompatibility.java but honestly speaking that's only a shot from the hip since I don't really know how to verify / test this scenario.

@Aeon512
Copy link
Contributor Author

Aeon512 commented May 14, 2016

Any news how this will progress?

@amuniz
Copy link
Member

amuniz commented May 16, 2016

@Aeon512 I didn't have time yet 😢 I'm a bit concerned about how this PR impacts freestyle compatibility and how the migration works, as we don't have too much automated tests for the former and none for the latter. So merging without manual testing is kind of dangerous (and they require time). Adding that tests is in my list, but feel free to add some if you feel good 😃

Migration tests are implemented in other plugins by using @LocalData, this is an example.

@Aeon512
Copy link
Contributor Author

Aeon512 commented Jun 4, 2016

@amuniz ping

@talcloudshare
Copy link

Any news? Specifically about JENKINS-34268?
Thanks

@Aeon512
Copy link
Contributor Author

Aeon512 commented Jun 30, 2016

@talcloudshare Unfortunately not. Sadly, I haven't heard from @amuniz
Working with a locally build version of the plugin for the moment.

@amuniz
Copy link
Member

amuniz commented Jul 1, 2016

Sorry, I didn't have time to review this, will do it as soon as I can.


@Initializer(after = InitMilestone.JOB_LOADED)
public static void beforeInitMilestonePluginsStarted() {
LOG.info("\n\n LOCKABLE RESOURCES COMPATABILITY INIT \n\n");
Copy link
Member

Choose a reason for hiding this comment

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

Better at FINE level.

@amuniz
Copy link
Member

amuniz commented Jul 7, 2016

The snippet generator is allowing to create:

lock(inversePrecedence: true, label: 'label1', quantity: 3, resource: 'resource1') {
    // some block
}

Without any warning. As label and resource parameters are mutual exclusive a validation should be shown, and a WARNING log in runtime saying that label will be ignored as resource is specified (not sure if that's the current behaviour, but it should be).

@Aeon512
Copy link
Contributor Author

Aeon512 commented Jul 9, 2016

@amuniz How can I mark parameters as mutual exclusive?

@amuniz
Copy link
Member

amuniz commented Jul 11, 2016

  1. Form validation and
  2. Exception throwing at runtime if both are set

throw new IllegalArgumentException("must specify resource");
}
this.resource = resource;
public LockStep() {
Copy link
Member

Choose a reason for hiding this comment

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

This is backward incompatible, but I fear there is no way to preserve it in this case.
Any call to to lock in the form lock ('my-resource') { ... } is going to fail.

@jglick any idea on how keep backward compatibility here?

Copy link
Member

Choose a reason for hiding this comment

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

This is preventing me to go ahead and merge. Unfortunately I don't see how keep backward compatibility here...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You are right that this breaks backward compatibility.
But only because the first pipeline implementation done by cloudbees only focused on the usage of resource names (and skipped the usage of labels and quantities all together).

One could argue that either

  • the first pipeline implementation by cloudbees shouldn't have been merged at all, because it focused only on 33% and did not provide an upgrade path (the problem you are looking at now)
  • that increasing the functionality for the pipeline implementation to the full feature set of the classic non-pipeline implementation is allowed to introduce breaking-changes since pipelines are still under heavy development.

Hence, I don't agree with your assumption that due to a incomplete (wrong) implementation done previously, we are not able to correct this implementation and do it right.
Sometimes a breaking change must happen. The sooner the better.

Copy link
Member

Choose a reason for hiding this comment

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

I may be missing something here but I don't think this has to be a breaking change. resource can be left in the constructor, and you can use @DataBoundSetter for the new fields. Both should work just fine.

@Aeon512
Copy link
Contributor Author

Aeon512 commented Jul 11, 2016

Do you have an example for a form validation in the pipeline snippet generator?
Couldn't get this to work.

@Aeon512
Copy link
Contributor Author

Aeon512 commented Jul 11, 2016

Anyone has an idea why the latest build got stuck? Didn't change much and locally everything works

@amuniz
Copy link
Member

amuniz commented Jul 11, 2016

Do you have an example for a form validation in the pipeline snippet generator?

It's regular Jenkins (stapler) validation, this is an example.

@Aeon512
Copy link
Contributor Author

Aeon512 commented Jul 26, 2016

@amuniz I have added the form validation.
However, I have no idea why the automatic build failed. Locally everything works fine.

@RemcoTukker
Copy link

Looks great! One question though: looking through the PR, it seems there's no way of finding out which resources you actually locked when using a label (eg through a global variable), or did I just miss it?

I think it would be very useful, at least when your resources are physical things. How else will you decide which resource actually to use after you acquired a lock on it? (Any one that's free is not good enough, because it could be free while someone else has a lock on it..)

@chancez
Copy link

chancez commented Dec 6, 2016

I'd love to see this. I currently need a better way than the built-in throttle functionality to limit the number of builds in a multibranch pipeline so that our Jenkins executors aren't overwhelmed with builds from a single repo with lots of branches/PRs.

@bmannix
Copy link

bmannix commented Dec 8, 2016

Is this PR still under development, or has it been abandoned?

@Aeon512
Copy link
Contributor Author

Aeon512 commented Dec 9, 2016

From my side this PR was finished. It builds locally without any problems and works fine since then.
Why the build on the Jenkins CI got stuck is unknown to me.
unfortunately Maintenance / Integration of Community PR seems to have a low priority at CloudBees...

@amuniz
Copy link
Member

amuniz commented Dec 9, 2016

Basically it was not merged because of the backward incompatible change, but @Vlatombe is pointing out that there isn't such backward incompatibility if the original @DataboundConstructor is kept and a @DataboundSetter is added for the new field.

The snippet generator is going to request for resource field always though, but I think it's a minor issue compared to the number of current calls the constructor change would break.

This is in my list, I can make and test the change by myself.

@amuniz amuniz closed this Dec 14, 2016
@amuniz amuniz reopened this Dec 14, 2016
@amuniz
Copy link
Member

amuniz commented Dec 14, 2016

@Vlatombe I just checked the snippet generation is completely broken if we keep the original constructor.

@Aeon512 I'm trying to fix it (will send some commits on top of yours).

amuniz added a commit to amuniz/lockable-resources-plugin that referenced this pull request Dec 14, 2016
@amuniz amuniz mentioned this pull request Dec 14, 2016
3 tasks
@amuniz
Copy link
Member

amuniz commented Dec 15, 2016

A follow up on this PR has been filed as #42 - it is ready for review and merge.

@amuniz amuniz closed this in #42 Dec 16, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants