-
-
Notifications
You must be signed in to change notification settings - Fork 274
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-44785] - Built-in request timeout support #174
base: master
Are you sure you want to change the base?
[JENKINS-44785] - Built-in request timeout support #174
Conversation
@@ -0,0 +1,108 @@ | |||
/* |
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 class is an adapted version of jenkinsci/workflow-support-plugin@c810b38
This pull request originates from a CloudBees employee. At CloudBees, we require that all pull requests be reviewed by other CloudBees employees before we seek to have the change accepted. If you want to learn more about our process please see this explanation. |
Why? I see no need for it. |
|
||
public <V,T extends Throwable> | ||
V call(@Nonnull Callable<V,T> callable, @CheckForNull Duration performTimeout, @CheckForNull Duration executionTimeout) | ||
throws IOException, T, InterruptedException { |
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.
What, no TimeoutException
?
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.
The call gets interrupted now instead of timeout. See the PR TODO list
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 interpreted the TODO in the PR as referring to methods added to VirtualChannel
with default
implementations. This is just being added to a class
so there is no Java 8 dependency. You chose the throws
clause for the method and I am arguing that it should be throwing TimeoutException
. See signatures of Future.get
and so on.
} | ||
|
||
public <V,T extends Throwable> | ||
V call(@Nonnull Callable<V,T> callable, @CheckForNull Duration performTimeout, @CheckForNull Duration executionTimeout) |
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 do not think executionTimeout
is necessary. Just keep it to performTimeout
. No one cares about the difference. A caller simply wants to ensure that a network call does not block forever.
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.
Yes and no. We want to prevent hanging of requests on both sides.
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 do not see any need for special infrastructure to control delays on the remote side, i.e., in the body of the callable. That is just up to the discretion of whoever is writing that callable—if it is in fact doing something which might block indefinitely, it may instead select a method variant with an appropriate timeout. But from the perspective of an RPC caller, what is important is just that the calling thread is not blocked for too long in networking.
t.setStackTrace(thread.getStackTrace()); | ||
LOGGER.log(Level.FINE, "Interrupting " + thread + " after " + delay + " " + unit, t); | ||
} | ||
thread.interrupt(); |
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 this utility is inappropriate here.
I introduced it in Pipeline code (later elsewhere) because I was calling predefined APIs (Channel.call
, ultimately) which offered no timeout (à la Future.get(long, TimeUnit)
), and from reading the source code I knew that the implementation would typically be inside an Object.wait()
loop in Request.call
, which I had no control over and which waited with no bound except a response, channel closing, or a thread interruption. So this was certainly a workaround.
But if you are implementing timeouts in remoting
itself, there is no reason to resort to that. You can simply make Request.call
not wait forever. It can wait
for the configured timeout, and not use the while
loop.
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.
But if you are implementing timeouts in remoting itself, there is no reason to resort to that. You can simply make Request.call not wait forever. It can wait for the configured timeout, and not use the while loop.
It will solve hanging of the calls only on one side of the channel. I want to address it on both
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.
See above. I think this is not the right approach.
* @since TODO | ||
*/ | ||
@Restricted(NoExternalUse.class) | ||
public class Timer { |
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.
As above, unnecessary if you implement timeouts in the more natural way.
@@ -45,6 +45,7 @@ | |||
import java.io.UnsupportedEncodingException; | |||
import java.lang.ref.WeakReference; | |||
import java.net.URL; | |||
import java.time.Duration; |
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.
Could use long
+ TimeUnit
if you wanted to keep Java 7 compatibility. (But I see no reason not to move to 8 immediately.)
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.
Yes, no reasons from the Jenkins community PoV since the LTS is on Java 8
One reason is that you ask for something to happen on the remote side and it takes a while to process and if it can not return within the default you do not want to waste resources continuing to do it. |
w.r.t.
So the body of the callable is free to impose any time limit it sees appropriate. For that matter a poorly written callable might be consuming hundreds of megs of heap for no good reason. This is no different from local method calls—not a concern of Remoting. |
As a maintainer of Remoting, I think having a timeout for such calls is important. Do you block the PR due to that? Or just "IMHO YAGNI"? |
Imho I agree with @jglick Timingboutvthe remote operation should not be a concern of the remoting api... (or at best it should be something that the caller opts-in e.g. By using a wrapper channel) I am inclined to object, but at this point I will just give a stern look and ask you to critically self-review ;-) |
Currently it's opt-in since the default timeout is "no timeout" |
But you are littering the API by multiplying methods. When somebody needs a timeout on the remote execution they probably just want you to provide them with a wrapping callable that does the timeout for them. That would simplify the API and simplify the implementation. IMHO less methods to choose from is better. I could probably go so far as to provide a wrapper to the callable for the caller timeout too so that, in effect, the caller just adds the timeouts to their callables
but it is fine to keep the local timeout as a parameter
as that way the |
That is essentially what I attempted to do with the
Well, -0.5. I think this PR is solving problems it did not need to solve, and solving the problems it did need to solve the wrong way. To reiterate, my original complaint in JENKINS-44785 was that, say, FilePath f;
try {
if (f.isDirectory()) {
// …
}
} catch (IOException | InterruptedException x) {
// …
} could block indefinitely due to problems in the network layer, being an example of one of the fundamental fallacies of distributed computing; and my request was for some variant like FilePath f;
try {
if (f.isDirectoryInterruptible()) {
// …
}
} catch (IOException | InterruptedException | TimeoutException x) {
// …
} or FilePath f;
try {
if (f.isDirectory(30, TimeUnit.SECONDS)) {
// …
}
} catch (IOException | InterruptedException | TimeoutException x) {
// …
} which would make explicit the fact that the network operation might hang for various arbitrary reasons and the caller must be prepared to deal with it. |
Premature to approve or reject PR until there is consensus on goals.
# Conflicts: # pom.xml # src/main/java/hudson/remoting/Channel.java # src/main/java/hudson/remoting/RemoteInvocationHandler.java # src/main/java/hudson/remoting/Request.java # src/test/java/hudson/remoting/ChannelTest.java
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 merged it, almost no mistakes
@@ -553,10 +555,10 @@ public void handle(Command cmd) { | |||
lastCommandReceivedAt = receivedAt; | |||
if (logger.isLoggable(Level.FINE)) { | |||
logger.fine("Received " + cmd); | |||
} else if (logger.isLoggable(Level.FINER)) { | |||
logger.log(Level.FINER, "Received command " + cmd, cmd.createdAt); |
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.
Merge defect To be fixed
close? |
Maybe, so long as |
I've been leaving it around as a reference for some possible ideas, thought the actual value is small. |
This is a PoC implementation of the timeout support in Remoting API, See one of the use-cases in JENKINS-44785
java.time.Duration
class, but it can be replaced if we stay on Java 7call()
default implementations in interfaces (withTimeoutException
s) to address the JENKINS-44785 request from @jglickchannel#callAsync()
should also support timeouts on the remote sideInterruptedException
?@reviewbybees @jglick