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

Add build step with timeout feature #61

Merged
merged 3 commits into from
Nov 5, 2016

Conversation

Jimilian
Copy link
Contributor

@Jimilian Jimilian commented Oct 24, 2016

Sometimes it's much better to have several small timeouts instead of one global one.

@Jimilian Jimilian changed the title Add build with step feature Add build step with timeout feature Oct 24, 2016
Copy link
Member

@ikedam ikedam left a comment

Choose a reason for hiding this comment

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

Do you plan to add test codes?


import hudson.Extension;
import hudson.Launcher;
import hudson.model.*;
Copy link
Member

Choose a reason for hiding this comment

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

Please don't use wildcard imports.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done



public class BuildStepWithTimeout extends Builder implements BuildStep {
private /* final */ BuildTimeOutStrategy strategy;
Copy link
Member

Choose a reason for hiding this comment

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

This can be final.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done


public class BuildStepWithTimeout extends Builder implements BuildStep {
private /* final */ BuildTimeOutStrategy strategy;
private BuildStep buildStep;
Copy link
Member

Choose a reason for hiding this comment

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

Would you consider to accept multiple steps?
That should make this feature more useful.

You can do that by using <f:hetero-list> instead of <f:dropdownDescriptor>.
This review may be helpful: https://github.com/jenkinsci/flexible-publish-plugin/pull/6/files

Copy link
Contributor Author

Choose a reason for hiding this comment

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

To be honest, I think it's too dangerous :)

From my perspective somebody should implement "multiple steps" build step once and all other plugins should just re-use it. I don't think that it's good idea to re-implement such logic, because even now I can't guarantee that all kind of build steps are supported (i.e. conditional steps doesn't work if it's used at child).

And in my case I don't need multiple steps - this "feature" was designed to split one global timeout on smallest chunks.

Copy link
Member

Choose a reason for hiding this comment

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

Actually, wrapping another buildstep is always dangerous.
Problems should happen even wrapping a single buildstep.
I can't get why you think it gets more dangerous when supporting multiple steps.

conditional steps doesn't work if it's used at child

I'll see why this happen.

Copy link
Member

Choose a reason for hiding this comment

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

Anyway, supporting multiple steps isn't required for this request.


public void setBuildStep(BuildStep buildStep) {
this.buildStep = buildStep;
}
Copy link
Member

Choose a reason for hiding this comment

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

I don't think you need this setter, and buildStep can be final.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done



public boolean perform(final Build<?,?> build, final Launcher launcher, final BuildListener listener) throws InterruptedException, IOException {
final Timer timer = new Timer("Timer-" + build.getDisplayName().replace(" ", "_"), true);
Copy link
Member

Choose a reason for hiding this comment

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

You can use Trigger.timer as in BuildTimeoutWrapper.
http://javadoc.jenkins-ci.org/hudson/triggers/Trigger.html#timer

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

return "Run with timeout";
}

public boolean isApplicable(Class<? extends AbstractProject> jobType) {
Copy link
Member

Choose a reason for hiding this comment

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

Let's annotate with Override.

BuildStep buildstep = BuildTimeOutUtility.bindJSONWithDescriptor(req, formData, "buildStep", BuildStep.class);
BuildTimeOutStrategy strategy = BuildTimeOutUtility.bindJSONWithDescriptor(req, formData, "strategy", BuildTimeOutStrategy.class);

if (!(strategy instanceof AbsoluteTimeOutStrategy || strategy instanceof DeadlineTimeOutStrategy)) {
Copy link
Member

Choose a reason for hiding this comment

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

Add a new method like TimeOutStrategy#isApplicableAsBuildStep and filter with that.
That's not a good idea to list up applicable classes in codes.

}

public List<BuildTimeOutStrategyDescriptor> getStrategies() {
return Jenkins.getInstance().getDescriptorList(BuildTimeOutStrategy.class);
Copy link
Member

Choose a reason for hiding this comment

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

You can apply TimeOutStrategy#isApplicableAsBuildStep also here.

@@ -65,6 +65,8 @@ public boolean perform(AbstractBuild<?, ?> build, BuildListener listener, long e
if (e != null) {
e.interrupt(Result.ABORTED);
}
build.setResult(Result.ABORTED);
Copy link
Member

Choose a reason for hiding this comment

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

What happens if you don't add this?
(You mean e.interrupt doesn't work?)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, it doesn't work for some reason. Interruption itself works as expected, but build result is different.

Copy link
Member

Choose a reason for hiding this comment

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

The result set with e.inturrupt isn't used as you suppressed InterruptedException.
I don't think it's good idea to suppress InterruptException as it may cause Jenkins work differently when you use BuildTimeOutWrapper and BuildStepWithTimeout.

As far as I tested the behavior, stacktraces aren't output into build logs (console logs), but are output only into system logs.
Can I know more details about why you want to suppress InterruptedException?

@@ -65,6 +61,7 @@ public boolean perform(AbstractBuild<?, ?> build, BuildListener listener, long e
if (e != null) {
e.interrupt(Result.FAILURE);
}
build.setResult(Result.FAILURE);
Copy link
Member

Choose a reason for hiding this comment

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

ditto

@Jimilian Jimilian force-pushed the build_step_with_timeout branch from d347ac7 to cc8d661 Compare October 26, 2016 15:20
@Jimilian
Copy link
Contributor Author

Ok, everything is done (I hope). I added a couple of tests for basic mechanic.

}

@Test
public void testTimeoutWasNotTriggered() throws IOException, ExecutionException, InterruptedException {
Copy link
Member

Choose a reason for hiding this comment

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

JFYI: It's easy for you to use throws Exception in test codes.

project.getBuildersList().add(step);

Future<FreeStyleBuild> future = project.scheduleBuild2(0, new Cause.UserIdCause());
FreeStyleBuild build = future.get();
Copy link
Member

Choose a reason for hiding this comment

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

You have to test the result of the build with JenkinsRule#assertBuildStatusSuccess or JenkinsRule#assertBuildStatus

Future<FreeStyleBuild> future = project.scheduleBuild2(0, new Cause.UserIdCause());
FreeStyleBuild build = future.get();

assertTrue(IOUtils.toString(build.getLogReader()).contains("Test"));
Copy link
Member

Choose a reason for hiding this comment

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

JFYI: JenkinsRule#assertLogContains is useful (but there isn't assertLogNotContains...)


try {
timer.schedule(task, delay);
return buildStep.perform((AbstractBuild) build, launcher, listener);
Copy link
Member

Choose a reason for hiding this comment

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

Please add generic types (AbstractBuild<?, ?>) as they are warned by compilers.

@ikedam
Copy link
Member

ikedam commented Oct 30, 2016

Would you tell me more details about "conditional steps doesn't work if it's used at child" ?
As far as I tested, it looks work with BuildStepWithTimeout as expected
(tested with Jenkins 1.651 and condition Always and Never work as expected).

I believe this is an important issue as conditional buildstep can be used as "multiple steps".

Also:
Add new tests to verify build results
@Jimilian
Copy link
Contributor Author

Jimilian commented Oct 31, 2016

Thanks for your suggestions - I made some refactoring for tests. Now even I'm satisfied with them :)

Would you tell me more details about "conditional steps doesn't work if it's used at child" ?

I don't have many details... just empty list of builders. No logs, no asserts, nothing in js console as well.
screen shot 2016-10-31 at 10 14 41

This happens on Jenkins ver. 1.632, but I wasn't able to repeat it on Jenkins ver. 1.651.3.

As far as I tested the behavior, stacktraces aren't output into build logs (console logs), but are output only into system logs.
Can I know more details about why you want to suppress InterruptedException?

I removed suppressing (as well as additional executions of setResult). In first place I mainly tested this plugin with "embedded" Jenkins version (1.466) and in 1.466 user receives exception in console, but this issue doesn't happen in 1.651.3.

@ikedam
Copy link
Member

ikedam commented Nov 5, 2016

As far as I know, InterruptedException isn't printed even in Jenkins-1.466.
Any way, I like the new change. Thanks!

This happens on Jenkins ver. 1.632, but I wasn't able to repeat it on Jenkins ver. 1.651.3.

Sorry, I missed that problem.
It's a bug of f:dropdownDescriptorSelector and fixed in Jenkins 1.645+ (jenkinsci/jenkins#1184).
Plugins can backport f:dropdownDescriptorSelector from Jenkins 1.645+ to fix that problem (like authorize-project-plugin).
You can create a new pull request to do that if you want to fix that problem

@ikedam ikedam merged commit 395ea8e into jenkinsci:master Nov 5, 2016
@ikedam
Copy link
Member

ikedam commented Nov 5, 2016

I plan to make a new release in the next weekend (11th or 12th Nov)

@Jimilian Jimilian deleted the build_step_with_timeout branch November 5, 2016 09:50
@ikedam
Copy link
Member

ikedam commented Nov 13, 2016

Released 1.18.
It will be available on the update center in a day.

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.

2 participants