Search code examples
javajbatchjberet

How can I synchronize a jBatch execution?


I'm writing a jBatch program with jBeret. I am currently doing like this.

final JobOperator operator = BatchRuntime.getJobOperator();
logger.debug("operator: {}", operator);

final long id = operator.start("some", null);
logger.debug("id: {}", id);

final JobExecution execution = operator.getJobExecution(id);
logger.debug("execution: {}", execution);

The problem is that execution seems run asynchronously and the main method simply returns.

The best I can do is looping until exit status is not null.

String status;
while ((status = execution.getExitStatus()) == null) {
    //logger.debug("sleeping");
    Thread.sleep(1000L);
}
logger.debug("status: {}", status);

Is there any other way to do this?


Solution

  • If you need to block-and-wait, as you've described, there is no other option, but have something like awaiCompletion() implemented.

    Your looping approach can be improved. Let's use ThreadPoolExecutor as an example. It has the following method:

        /**
         * Blocks until all tasks have completed execution after a shutdown
         * request, or the timeout occurs, or the current thread is
         * interrupted, whichever happens first.
         *
         * @param timeout the maximum time to wait
         * @param unit the time unit of the timeout argument
         * @return {@code true} if this executor terminated and
         *         {@code false} if the timeout elapsed before termination
         * @throws InterruptedException if interrupted while waiting
         */
        boolean awaitTermination(long timeout, TimeUnit unit)
            throws InterruptedException;
    

    and here is the implementation:

        public boolean awaitTermination(long timeout, TimeUnit unit)
            throws InterruptedException {
            long nanos = unit.toNanos(timeout);
            final ReentrantLock mainLock = this.mainLock;
            mainLock.lock();
            try {
                for (;;) {
                    if (runStateAtLeast(ctl.get(), TERMINATED))
                        return true;
                    if (nanos <= 0)
                        return false;
                    nanos = termination.awaitNanos(nanos);
                }
            } finally {
                mainLock.unlock();
            }
        }
    

    Please note:

    • infinite loop should always have exit condition defined
    • in your case timeout is must-have, because it is unlikely you are ready for an endless wait
    • naturally you have to know whether it was timeout or job termination

    So, here is an adapted version:

        public static boolean awaitTermination(JobExecution execution, long timeout) throws InterruptedException {
            final long limit = System.currentTimeMillis() + timeout;
            for (;;) {
                if (null != execution.getExitStatus()) {
                    return true;
                }
    
                if (System.currentTimeMillis() >= limit) {
                    return false;
                }
    
                Thread.sleep(timeout/10);            
            }
        }