Hello,
I am trying to diagnose a few remoting related issues in the unity3d plugin
(https://github.com/jenkinsci/unity3d-plugin/)
I am unable to reproduce the issues so far but would appreciate any insight
into my analysis (and design of the plugin).
Plugin function and design:
The plugins basically executes a program (Unity3d) which happens to write
its output into a file (hereafter called logFile). I pipe this file into
the console as it is written. To achieve this remote piping I used the
following design:
3 elements are created:
* a org.jenkinsci.plugins.unity3d.io.Pipe consisting of a PipedInputStream
and a PipedOutputStream. This outputstream is wrapped into a
RemoteOutputStream if the launcher is to be executed remotely.
* a long running Async Callable is passed to the launcher channel. This
closure, a PipeFileAfterModificationAction instance, detects that the
logFile is started being written and copies from it recursively into the
pipe until interrupted. It then closes the output in a finally
* a org.jenkinsci.plugins.unity3d.io.StreamCopyThread reads from the pipe
on the master and copies it into the job console.
The issues that some users are experiencing:
* the logFile isn't fully pasted into the console
* the pipe is broken:
java.io.IOException: Pipe broken
at java.io.PipedInputStream.read(PipedInputStream.java:322)
at java.io.PipedInputStream.read(PipedInputStream.java:378)
at java.io.InputStream.read(InputStream.java:101)
at
org.jenkinsci.plugins.unity3d.io.StreamCopyThread.run(StreamCopyThread.java:64)
It seems like these errors
* only happen when used in distributed environmenrts
* when the second happens, the first one as well.
Analysis:
I looked into the "Pipe broken" issue and I believe something is fishy in
my design.
Ideally I want to:
* wait for the Unity3d command to finish execution
* stop the thread reading the logFile on the remote side
* pipe everything back into the console
* close things gracefully
To achieve this, I do this in the finally block of the unity3d plugin
execution:
// wait for some time - see
https://github.com/jenkinsci/unity3d-plugin/commit/d792376afd67579f313043e7c701cf2559df02bd
Thread.sleep(1000);
// stop the piping
if (!futureReadBytes.isDone()) {
futureReadBytes.cancel(true);
}
// wait for the copy
try {
copierThread.join();
if (copierThread.getFailure() != null) {
For the "Pipe broken" issue, my clean closing objective isn't reached. The
StreamCopyThread fails while copying, i.e. it detects that the Thread that
writes into the PipedInputStream (named
"Computer.threadPoolForRemoting(...)" is dead (isAlive()==false) before the
read() detects the eof (-1).
Why does it die, I am not sure, this thread is managed by the remoting
framework.
Question #1: futureReadBytes.cancel(true)
This if my understanding is correct should send a Cancel command
asynchronously to the remote end.
I expect this one to interrupt the reading of the
PipeFileAfterModificationAction which would close the stream in its finally
and thus terminate the async operation then the thread that reads into the
pipe.
But could the cancel cause the local thread to die before the remote action
is terminated properly ?
Question #2: lack of flushing could be the cause of the incomplete piping
Am I missing some flushing somewhere ? This could happen at lots of levels.
I don't see much flushing in the jenkins StreamCopyTread either.
Question #3: better design
I believe it would be better if I didn't have a long running async Callable
to pipe the logFile, but something I could signal to stop from the client
side instead of having to use cancel(). Any tip on achieving this in a way
that fits with the remoting library ?
Some ideas I've had:
* get rid of the PipeFileAfterModificationAction action by forcing the
writing of the output into a newly created logFile and use a standard
StreamCopyThread to pipe it. That way I don't have to detect the start of
the operation. This would still require the synchronization of the stop of
the command.
* create a wrapper script that uses OS capabilities to run the command and
pipe the logFile to its standard output, letting the jenkins side of it
execute a single command, and not caring about the piping. I know how to do
this on Unix but not on Windows. Otherwise the script could be a Java
wrapper, but this is a bit overkill it seems.
Thanks for your insights,
Cheers,
Jerome
--
You received this message because you are subscribed to the Google Groups
"Jenkins Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.