I've detected a strange behavior when using the read() method provided by JTOpen's KeyedDataQueue
class.
I've set an 90s timeout and for 99% of read executions when the timeout is reached my calling method execution is resumed.
As for the other 1% the timeout isn't considered/reached and my calling method stays hung...
After searching a bit I found this post:
http://archive.midrange.com/java400-l/201112/msg00056.html
Basically it confirms what I suspected:
"I also found that the DataQueue.read() timeout functionality is server side so if the TCP/IP connection is silently torn down (which I believe is the underlying cause of this) it will still hang. "
I'm using version 7.2 of JTOpen and I realize that version 7.9 is already out there. I didn't update to 7.9 because I have a lot of critical applications using 7.2 that are stable and really this is the first real scenario that makes me consider updating to 7.9.
In order to help me with that decision I would really like your feedback, especially from those of you that came across this situation and eventually solved it by upgrading JTOpen.
Specifically, are there workarounds for this issue, and does upgrading JTOpen help with this? Will upgrading JTOpen to 7.9 break anything that was working in 7.2?
As mentioned above the dataqueue read timeout is server side. If the TCP connection between the iSeries and the client stalls or dies the client will wait until the socket times out. My solution is to institute a fail safe interrupter to stop a stalled read. Here is a quick code sample of how this can be done.
public class DataQueueListenerExample {
//This executes our Interrupter after the specified delay.
public final ScheduledThreadPoolExecutor interruptExecuter = new ScheduledThreadPoolExecutor(1);
//the dataqueue object.
protected DataQueue dataqueue;
public DataQueueEntry read(int wait)
{
ScheduledFuture<?> future = null;
try {
//create our fail safe interrupter. We only want it to
//interrupt when we are sure the read has stalled. My wait time is 15 seconds
future = createInterrupter(wait * 2, TimeUnit.SECONDS);
//read the dataqueue
return this.dataqueue.read(wait);
} catch (AS400SecurityException e) {
} catch (ErrorCompletingRequestException e) {
} catch (IOException e) {
} catch (IllegalObjectTypeException e) {
} catch (InterruptedException e) {
//The read was interrupted by our Interrupter
return null;
} catch (ObjectDoesNotExistException e) {
} finally{
//Cancel our interrupter
if(future != null && !future.isDone())
future.cancel(true);
Thread.interrupted();//clear the interrupted flag
interruptExecuter.shutdown();
}
return null;
}
public ScheduledFuture<?> createInterrupter(long timeout,TimeUnit timeunit)
{
return interruptExecuter.schedule(new Interrupter(),timeout,timeunit);
}
class Interrupter implements Runnable
{
final Thread parent;
Interrupter()
{
this.parent = Thread.currentThread();
}
@Override
public void run() {
parent.interrupt();
}
}
}
I strongly recommend recreating the DataQueue object on a new AS400 connection after an InterruptedException. Chances are that your AS400 connection is stalled. Thread.interrupt is very useful, but use it with caution.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With