-
-
Notifications
You must be signed in to change notification settings - Fork 8.7k
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-72111] Add Lifecycle#set
#8555
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
@@ -28,18 +28,22 @@ | |||||||||
import edu.umd.cs.findbugs.annotations.NonNull; | ||||||||||
import hudson.ExtensionPoint; | ||||||||||
import hudson.Functions; | ||||||||||
import hudson.PluginManager; | ||||||||||
import hudson.Util; | ||||||||||
import java.io.File; | ||||||||||
import java.io.IOException; | ||||||||||
import java.io.UncheckedIOException; | ||||||||||
import java.lang.reflect.InvocationTargetException; | ||||||||||
import java.nio.file.Files; | ||||||||||
import java.util.Objects; | ||||||||||
import java.util.concurrent.TimeUnit; | ||||||||||
import java.util.logging.Level; | ||||||||||
import java.util.logging.Logger; | ||||||||||
import jenkins.model.Jenkins; | ||||||||||
import jenkins.util.SystemProperties; | ||||||||||
import org.apache.commons.io.FileUtils; | ||||||||||
import org.kohsuke.accmod.Restricted; | ||||||||||
import org.kohsuke.accmod.restrictions.Beta; | ||||||||||
|
||||||||||
/** | ||||||||||
* Provides the capability for starting/stopping/restarting/uninstalling Hudson. | ||||||||||
|
@@ -57,9 +61,8 @@ | |||||||||
|
||||||||||
/** | ||||||||||
* Gets the singleton instance. | ||||||||||
* | ||||||||||
* @return never null | ||||||||||
*/ | ||||||||||
@NonNull | ||||||||||
public static synchronized Lifecycle get() { | ||||||||||
if (INSTANCE == null) { | ||||||||||
Lifecycle instance; | ||||||||||
|
@@ -136,6 +139,19 @@ | |||||||||
return INSTANCE; | ||||||||||
} | ||||||||||
|
||||||||||
/** | ||||||||||
* Sets the singleton instance. | ||||||||||
* Appropriate for implementations defined in plugins, | ||||||||||
* since {@link #get} may be called before plugins are initialized, | ||||||||||
* and so it is not safe to pass a plugin-defined class to the system property {@code hudson.lifecycle} | ||||||||||
* despite the use of {@link PluginManager#uberClassLoader}. | ||||||||||
Comment on lines
+145
to
+147
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. While a veto-type method in jenkins/core/src/main/java/hudson/lifecycle/Lifecycle.java Lines 83 to 86 in d1b8473
I do not think #8555 (comment) is a real issue; it just means that for example a plugin-provided lifecycle cannot override |
||||||||||
* @since TODO | ||||||||||
*/ | ||||||||||
@Restricted(Beta.class) | ||||||||||
public static synchronized void set(@NonNull Lifecycle lifecycle) { | ||||||||||
INSTANCE = Objects.requireNonNull(lifecycle); | ||||||||||
} | ||||||||||
|
||||||||||
/** | ||||||||||
* If the location of {@code jenkins.war} is known in this life cycle, | ||||||||||
* return it location. Otherwise return null to indicate that it is unknown. | ||||||||||
|
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.
this comment is contradictory to me.
if this method is appropriate for plugins, but itself may be called before plugins are initialized, how can a plugin ensure that they can call
set
beforeget
as any consumers ofget
can rightly assume that the lifecycle is fixed.the answer is they can not - so it is not really "safe" to be called in a plugin.
once
get
is called - to all purposesINSTANCE
should be final and never change.You could probably demonstrate this by throwing an exception if
INSTANCE
is non null (which means get has been called)so whilst setting the property is not safe to use with an implementation from a plugin equally this new method appears to not be safe as callers of
get
can get intermediate responses.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.
It cannot, but it can call
set
in an@Initializer
or otherwise during startup.Why would a consumer make that assumption? I did a search of @jenkinsci sources and found no example of a consumer doing anything with the return value other than immediately calling some method on 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.
which means if startup fails the lifecycle will not be correctly replaced leading to "the wrong" lifecyle handling the issue?
Because it was a single initialized only once in code.
an example (but a bad one) is
jenkins/core/src/main/java/hudson/lifecycle/WindowsInstallerLink.java
Lines 267 to 288 in 7d2b484
I hope to rip that example out in #8523 so this becomes a moot point.
I think this just needs some clearer documentation that this is super advanced and you should not normally do this - and it you do that you will not be called back during early initialisation like a regular
Lifecycle
and that even changing it could cause other plugin code that is obtaining the lifecycle (say to check if you can restart once) may not observe any changes in the lifecycle. (or documewnt in the get that the lifecycle can change at runtime)esp the class level comment is now incorrect about how the Lifecycle is found.
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.
Well, it is marked
Beta
, but yes documentation should be adjusted.There are probably other ways to approach the problem. Currently
jenkins/core/src/main/java/hudson/model/RestartListener.java
Lines 24 to 27 in 7d2b484
jenkins/core/src/main/java/jenkins/model/Jenkins.java
Lines 4649 to 4663 in 7d2b484
jenkins/core/src/main/java/jenkins/model/Jenkins.java
Lines 4689 to 4710 in 7d2b484
Lifecycle
in a module in the same class loader asjenkins-core.jar
, though this is logistically more complicated because then you need to package this module somewhere, and it cannot easily call other plugin methods, etc. The current patch is more expedient.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.
(for the avoidance of doubt my comments are non blocking)