use of org.eclipse.scout.rt.platform.util.concurrent.ThreadInterruptedError in project scout.rt by eclipse.
the class JmsMomImplementorTest method testRequestReplyCancellationInternal.
private void testRequestReplyCancellationInternal(final IBiDestination<String, String> destination) throws InterruptedException {
final CountDownLatch neverLatch = new CountDownLatch(1);
final CountDownLatch setupLatch = new CountDownLatch(1);
final CountDownLatch verifyLatch = new CountDownLatch(2);
final AtomicBoolean requestorInterrupted = new AtomicBoolean();
final AtomicBoolean replierInterrupted = new AtomicBoolean();
final AtomicBoolean replierCancelled = new AtomicBoolean();
// Subscribe for the destination
m_disposables.add(MOM.reply(JmsTestMom.class, destination, new IRequestListener<String, String>() {
@Override
public String onRequest(IMessage<String> request) {
setupLatch.countDown();
try {
neverLatch.await();
} catch (InterruptedException e) {
replierInterrupted.set(true);
} finally {
replierCancelled.set(RunMonitor.CURRENT.get().isCancelled());
verifyLatch.countDown();
}
return request.getTransferObject().toUpperCase();
}
}));
// Initiate 'request-reply' communication
final FinalValue<String> testee = new FinalValue<>();
IFuture<Void> requestFuture = Jobs.schedule(new IRunnable() {
@Override
public void run() throws Exception {
try {
String result = MOM.request(JmsTestMom.class, destination, "hello world");
testee.set(result);
} catch (ThreadInterruptedError e) {
requestorInterrupted.set(true);
} finally {
verifyLatch.countDown();
}
}
}, Jobs.newInput().withName("initiator").withExecutionHint(m_testJobExecutionHint));
// Wait until reply message processing started
setupLatch.await();
// Cancel the publishing thread
requestFuture.cancel(true);
// wait for request / reply interrupted
verifyLatch.await();
// Verify
assertTrue(requestorInterrupted.get());
assertTrue(replierInterrupted.get());
assertTrue(replierCancelled.get());
assertFalse(testee.isSet());
}
use of org.eclipse.scout.rt.platform.util.concurrent.ThreadInterruptedError in project scout.rt by eclipse.
the class JmsMomImplementor method request.
@Override
public <REQUEST, REPLY> REPLY request(final IBiDestination<REQUEST, REPLY> destination, final REQUEST requestObject, final PublishInput input) {
assertTrue(m_requestReplyEnabled, "'request-reply' messaging is not enabled for this MOM");
assertNotNull(destination, "destination not specified");
assertNotNull(input, "publishInput not specified");
assertFalse(input.isTransactional(), "transactional mode not supported for 'request-reply' communication");
// JMS message ID not applicable because unknown until sent
final String replyId = String.format("scout.mom.requestreply.uid-%s", UUID.randomUUID());
final IBlockingCondition condition = Jobs.newBlockingCondition(true);
IFuture<Message> requestFuture = Jobs.schedule(new Callable<Message>() {
@Override
public Message call() throws Exception {
try {
return requestImpl(destination, requestObject, input, replyId);
} finally {
condition.setBlocking(false);
}
}
}, newJobInput().withName("request on {}", destination.getName()).withExceptionHandling(BEANS.get(MomExceptionHandler.class), false).withRunContext(RunContexts.copyCurrent(true).withDiagnostics(BEANS.all(IJmsRunContextDiagnostics.class))));
try {
long timeout = input.getRequestReplyTimeout();
if (timeout == PublishInput.INFINITELY) {
condition.waitFor();
} else {
condition.waitFor(timeout, TimeUnit.MILLISECONDS);
}
Message responseMessage = requestFuture.awaitDoneAndGet();
return transform(responseMessage, replyId, resolveMarshaller(destination));
} catch (JMSException e) {
throw BEANS.get(DefaultRuntimeExceptionTranslator.class).translate(e);
} catch (ThreadInterruptedError | TimedOutError e) {
// send cancel to replier
cancelRequest(replyId);
// cancel request job
if (requestFuture.cancel(true)) {
requestFuture.awaitDone();
}
throw e;
}
}
use of org.eclipse.scout.rt.platform.util.concurrent.ThreadInterruptedError in project scout.rt by eclipse.
the class HttpServiceTunnel method tunnel.
@Override
protected ServiceTunnelResponse tunnel(final ServiceTunnelRequest serviceRequest) {
final long requestSequence = serviceRequest.getRequestSequence();
// Create the Callable to be given to the job manager for execution.
final RemoteServiceInvocationCallable remoteInvocationCallable = createRemoteServiceInvocationCallable(serviceRequest);
// Register the execution monitor as child monitor of the current monitor so that the service request is cancelled once the current monitor gets cancelled.
// Invoke the service operation asynchronously (to enable cancellation) and wait until completed or cancelled.
final IFuture<ServiceTunnelResponse> future = Jobs.schedule(remoteInvocationCallable, Jobs.newInput().withRunContext(RunContext.CURRENT.get().copy()).withName(createServiceRequestName(requestSequence)).withExceptionHandling(null, // do not handle uncaught exceptions because typically invoked from within a model job (might cause a deadlock, because ClientExceptionHandler schedules and waits for a model job to visualize the exception).
false)).whenDone(new IDoneHandler<ServiceTunnelResponse>() {
@Override
public void onDone(DoneEvent<ServiceTunnelResponse> event) {
if (event.isCancelled()) {
remoteInvocationCallable.cancel();
}
}
}, RunContext.CURRENT.get().copy().withRunMonitor(// separate monitor to not cancel this cancellation action.
BEANS.get(RunMonitor.class)));
try {
return future.awaitDoneAndGet();
} catch (ThreadInterruptedError e) {
// NOSONAR
// Ensure the monitor to be cancelled once this thread is interrupted to cancel the remote call.
future.cancel(true);
// Interruption has precedence over computation result or computation error.
return new ServiceTunnelResponse(new ThreadInterruptedError(TEXTS.get("UserInterrupted")));
} catch (FutureCancelledError e) {
// Cancellation has precedence over computation result or computation error.
return new ServiceTunnelResponse(new FutureCancelledError(TEXTS.get("UserInterrupted")));
}
}
use of org.eclipse.scout.rt.platform.util.concurrent.ThreadInterruptedError in project scout.rt by eclipse.
the class RemoteServiceInvocationCallable method call.
/**
* Invokes the remote service operation.
*
* @return {@link IServiceTunnelResponse}; is never <code>null</code>.
*/
@Override
public ServiceTunnelResponse call() throws Exception {
long nBytes = 0;
final long tStart = LOG.isDebugEnabled() ? System.nanoTime() : 0L;
try {
// Create the request.
final ByteArrayOutputStream requestMessage = new ByteArrayOutputStream();
m_tunnel.getContentHandler().writeRequest(requestMessage, m_serviceRequest);
requestMessage.close();
final byte[] requestData = requestMessage.toByteArray();
nBytes = requestData.length;
// Send the request to the server.
HttpResponse resp = m_tunnel.executeRequest(m_serviceRequest, requestData);
// Receive the response.
m_tunnel.interceptHttpResponse(resp, m_serviceRequest);
if (resp.getStatusCode() != 0 && (resp.getStatusCode() < 200 || resp.getStatusCode() > 299)) {
// request failed
return new ServiceTunnelResponse(new HttpException(resp.getStatusCode()));
}
try (InputStream in = resp.getContent()) {
return m_tunnel.getContentHandler().readResponse(in);
}
} catch (IOException e) {
if (Thread.currentThread().isInterrupted()) {
LOG.debug("Ignoring IOException for interrupted thread.", e);
return new ServiceTunnelResponse(new ThreadInterruptedError("Thread is interrupted.", e));
} else if (RunMonitor.CURRENT.get().isCancelled()) {
LOG.debug("Ignoring IOException for cancelled thread.", e);
return new ServiceTunnelResponse(new FutureCancelledError("RunMonitor is cancelled.", e));
}
throw e;
} finally {
if (LOG.isDebugEnabled()) {
final long elapsedMillis = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - tStart);
LOG.debug("TIME {}.{} {}ms {} bytes", m_serviceRequest.getServiceInterfaceClassName(), m_serviceRequest.getOperation(), elapsedMillis, nBytes);
}
}
}
use of org.eclipse.scout.rt.platform.util.concurrent.ThreadInterruptedError in project scout.rt by eclipse.
the class JobStateTest method testBlockedAndInterrupted.
@Test
// regression
@Times(100)
public void testBlockedAndInterrupted() throws ThreadInterruptedError, java.lang.InterruptedException {
JobEventCaptureListener captureListener = new JobEventCaptureListener();
Jobs.getJobManager().addListener(captureListener);
final IExecutionSemaphore mutex = Jobs.newExecutionSemaphore(1);
final IBlockingCondition condition = Jobs.newBlockingCondition(true);
final AtomicReference<Thread> workerThread = new AtomicReference<>();
final IFuture<Void> future1 = Jobs.schedule(new IRunnable() {
@Override
public void run() throws Exception {
workerThread.set(Thread.currentThread());
assertSame(JobState.RUNNING, IFuture.CURRENT.get().getState());
try {
condition.waitFor("ABC");
fail("interruption expected");
} catch (ThreadInterruptedError e) {
assertTrue(Thread.interrupted());
// Restore interrupted status
Thread.currentThread().interrupt();
assertTrue(mutex.isPermitOwner(IFuture.CURRENT.get()));
assertSame(JobState.RUNNING, IFuture.CURRENT.get().getState());
}
}
}, Jobs.newInput().withName("job-1").withExecutionSemaphore(mutex));
// Wait until job-1 is running
JobTestUtil.waitForState(future1, JobState.WAITING_FOR_BLOCKING_CONDITION);
// Interrupt worker thread
workerThread.get().interrupt();
future1.awaitDoneAndGet();
assertTrue(future1.isDone());
assertFalse(future1.isCancelled());
// wait because permit is released just after done (max 30s)
JobTestUtil.waitForPermitCompetitors(mutex, 0);
// verify events
int i = -1;
List<JobEvent> capturedEvents = captureListener.getCapturedEvents();
List<JobState> capturedFutureStates = captureListener.getCapturedFutureStates();
i++;
assertStateChangedEvent(future1, JobState.SCHEDULED, capturedEvents.get(i));
assertEquals(JobState.SCHEDULED, capturedFutureStates.get(i));
i++;
assertStateChangedEvent(future1, JobState.WAITING_FOR_PERMIT, capturedEvents.get(i));
assertEquals(JobState.WAITING_FOR_PERMIT, capturedFutureStates.get(i));
i++;
assertStateChangedEvent(future1, JobState.RUNNING, capturedEvents.get(i));
assertEquals(JobState.RUNNING, capturedFutureStates.get(i));
i++;
assertHintChangedEvent(JobEventType.JOB_EXECUTION_HINT_ADDED, future1, "ABC", capturedEvents.get(i));
assertEquals(JobState.RUNNING, capturedFutureStates.get(i));
i++;
assertBlockedStateEvent(future1, condition, capturedEvents.get(i));
assertEquals(JobState.WAITING_FOR_BLOCKING_CONDITION, capturedFutureStates.get(i));
i++;
assertStateChangedEvent(future1, JobState.WAITING_FOR_PERMIT, capturedEvents.get(i));
assertEquals(JobState.WAITING_FOR_PERMIT, capturedFutureStates.get(i));
i++;
assertHintChangedEvent(JobEventType.JOB_EXECUTION_HINT_REMOVED, future1, "ABC", capturedEvents.get(i));
assertEquals(JobState.WAITING_FOR_PERMIT, capturedFutureStates.get(i));
i++;
// due to interruption
assertStateChangedEvent(future1, JobState.RUNNING, capturedEvents.get(i));
assertEquals(JobState.RUNNING, capturedFutureStates.get(i));
i++;
assertStateChangedEvent(future1, JobState.DONE, capturedEvents.get(i));
assertEquals(JobState.DONE, capturedFutureStates.get(i));
assertEquals(i + 1, capturedEvents.size());
}
Aggregations