/*
* Copyright (c) 2015 Red Hat, Inc. and/or its affiliates.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Cheng Fang - Initial API and implementation
*/
package org.jberet.testapps.throttle;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import javax.batch.runtime.BatchStatus;
import org.jberet.runtime.JobExecutionImpl;
import org.jberet.testapps.common.AbstractIT;
import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test;
/**
* The test job has a chunk-step with 10 partitions. When the test client starts many jobs one after another,
* all available threads in the pool may be quickly used up, and by the time some job execution needs to allocate
* threads to partitions, there is no more threads available, hence the deadlock.
* <p/>
* The purpose of the tests is to verify that the batch runtime should be able to detect the potential deadlock risk
* when starting a new job executions, and queue it up for later execution when threads are available, to avoid deadlock.
* <p/>
* The batch runtime is configured to have a fixed thread pool of size 10, in src/main/resources/jberet.properties
*
* @see <a href="https://issues.jboss.org/browse/JBERET-180">JBERET-180</a>
*/
public class ThrottleIT extends AbstractIT {
static final String jobName = "throttle";
/**
* Starts the test job 300 times, one after another or concurrently.
* The test has a chunk-type step with 10 partitioins.
* Verifies the job submission is properly throttled and the these jobs should complete successfully without deadlock.
*
* @throws Exception
*/
@Test
public void start300() throws Exception {
runTest(300, true);
}
@Ignore
@Test
public void start1000() throws Exception {
runTest(1000, true);
}
@Ignore
@Test
public void start2100() throws Exception {
runTest(2100, true);
}
/**
*
* @param count number of times to start the test job
* @param concurrent a flag whether to start the test job serially or concurently
*
* @throws Exception
*/
private void runTest(final int count, final boolean concurrent) throws Exception {
final List<Long> jobExecutionIds = new CopyOnWriteArrayList<Long>();
if(concurrent) {
final List<Thread> threads = new ArrayList<Thread>();
for (int i = 0; i < count; i++) {
final Thread t = new Thread(new Runnable() {
@Override
public void run() {
jobExecutionIds.add(jobOperator.start(jobName, params));
}
});
threads.add(t);
t.start();
}
for (final Thread t : threads) {
t.join();
}
} else {
for (int i = 0; i < count; ++i) {
jobExecutionIds.add(jobOperator.start(jobName, params));
}
}
for (final Long id : jobExecutionIds) {
final JobExecutionImpl exe = (JobExecutionImpl) jobOperator.getJobExecution(id);
awaitTermination(exe);
Assert.assertEquals(BatchStatus.COMPLETED, exe.getBatchStatus());
}
System.out.printf("%nJobExecution ids: %s%n", jobExecutionIds);
}
}