Question

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?

Was it helpful?

Solution

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top