I know that I can throw an exception to suppress further executions of task that has been scheduled for repeated execution inside a ScheduledExecutorService (see this question).
I also know that I can setRemoveOnCancelPolicy(true) to make sure cancelled tasks are removed from the queue.
My questions are: Is the task actually removed from the scheduler also when I throw an exception from within it? Does this happen by implicitly cancelling the future? If yes, does this mean that setRemoveOnCancelPolicy() also bears on this case?
Couldn't find anything in the Javadocs.
I was wondering the same, couldn't find anything in the docs, so I tried it out. Observation:
Throwing a RuntimeException marks the future as done, not cancelled.
The Runnable is removed from the scheduler's queue, regardless of setRemoveOnCancelPolicy().
Try it out yourself:
public class SchedulerTest {
protected final Logger log = LoggerFactory.getLogger(this.getClass());
#Test
public void schedulerExecutionException() throws Exception {
log.info("Test: schedulerExecutionException");
ScheduledThreadPoolExecutor sched = new ScheduledThreadPoolExecutor(2);
sched.setRemoveOnCancelPolicy(true);
ScheduledFuture future1 = sched.scheduleAtFixedRate(new Runnable() {
int counter = 0;
#Override
public void run() {
log.info("Runnable 1: "+ ++counter);
if (counter >= 2) {
log.info("Runnable 1: BOOOM");
throw new RuntimeException("boom");
}
}
}, 1, 1, TimeUnit.SECONDS);
ScheduledFuture future2 = sched.scheduleAtFixedRate(new Runnable() {
int counter = 0;
#Override
public void run() {
log.info("Runnable 2: "+ ++counter);
}
}, 1, 1, TimeUnit.SECONDS);
long cutoff = new Date().getTime() + 6000;
while (new Date().getTime() < cutoff) {
log.info("Scheduler Queue size: "+ sched.getQueue().size());
log.info("Future 1: is "+ (future1.isCancelled() ? "" : "not ") +"cancelled, is "+ (future1.isDone()? "" : "not ") +"done");
log.info("Future 2: is "+ (future2.isCancelled() ? "" : "not ") +"cancelled, is "+ (future2.isDone()? "" : "not ") +"done");
Thread.sleep(1000);
}
assertEquals(sched.getQueue().size(), 1);
future2.cancel(true);
log.info("Scheduler Queue size: "+ sched.getQueue().size());
log.info("Future 1: is "+ (future1.isCancelled() ? "" : "not ") +"cancelled, is "+ (future1.isDone()? "" : "not ") +"done");
log.info("Future 2: is "+ (future2.isCancelled() ? "" : "not ") +"cancelled, is "+ (future2.isDone()? "" : "not ") +"done");
assertEquals(sched.getQueue().size(), 0);
sched.shutdownNow();
}
}
Related
Let's say I have a long chain of Monos. Some monos in the chain might return Mono.empty().
I can recover with switchIfEmpty, but I'd like to know which mono raised the empty (maybe so I can know where to add smarter empty handling).
Is there a way to programmatically get this information?
Silly example. In cases where I return how did I get here?, how I can know if the first flatMap or the second flatMap triggered the empty handler?
Mono.just("data")
.flatMap(t -> {
if (System.currentTimeMillis() % 2 == 0) {
return Mono.empty();
}
return Mono.just("happy1");
})
.flatMap(t -> {
if (System.currentTimeMillis() % 2 == 0) {
return Mono.empty();
}
return Mono.just("happy2");
})
.map(s -> {
return "successful complete: " + s;
})
.switchIfEmpty(Mono.fromCallable(() -> {
return "how did I get here?";
}))
.block();
Due to the dynamic nature of Flux and Mono, and to the fact that the onComplete signal is considered neutral enough that it is usually just passed through, there is no generic solution for this.
In your particular example, you could replace the Mono.empty() with something like Mono.empty().doOnComplete(() -> /* log something */).
You could even directly perform the logging in the if block, but the decorated empty trick is probably adaptable to more situations.
Another possibility is to turn emptiness into an error, rather than a switch on onComplete signal.
Errors are less neutral, so there are ways to enrich them for debugging purposes. For instance, with a .checkpoint("flatMapX") statement after each flatMap, you'd get additional stacktrace parts that would point to the flatMap which failed due to emptyness.
A way of turning emptiness to error in Mono is .single(), which will enforce exactly one onNext() or propagate onError(NoSuchElementException).
One thing to keep in mind with this trick is that the placement of checkpoint matters: it MUST be AFTER the single() so that the error raised from the single() gets detected and enriched.
So if I build on your snippet:
static final String PARSEABLE_MARKER = "PARSEABLE MARKER: <";
static final char MARKER_END = '>';
String parseLocation(Exception e) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
String trace = sw.toString();
int start = trace.indexOf(PARSEABLE_MARKER);
if (start > 0) {
trace = trace.substring(start + PARSEABLE_MARKER.length());
trace = trace.substring(0, trace.indexOf(MARKER_END));
return trace;
}
return "I don't know";
}
String testInner() {
Random random = new Random();
final boolean first = random.nextBoolean();
return Mono.just("data")
.flatMap(t -> {
if (System.currentTimeMillis() % 2 == 0 && first) {
return Mono.empty();
}
return Mono.just("happy1");
})
.single()
.checkpoint(PARSEABLE_MARKER + "the first flatMap" + MARKER_END)
.flatMap(t -> {
if (System.currentTimeMillis() % 2 == 0 && !first) {
return Mono.empty();
}
return Mono.just("happy2");
})
.single()
.checkpoint(PARSEABLE_MARKER + "the second flatMap" + MARKER_END)
.map(s -> {
return "successful complete: " + s;
})
.onErrorResume(NoSuchElementException.class, e ->
Mono.just("how did I get here? " + parseLocation(e)))
.block();
}
This can be run in a loop in a test for instance:
#Test
void test() {
int successCount = 0;
int firstCount = 0;
int secondCount = 0;
for (int i = 0; i < 100; i++) {
String message = testInner();
if (message.startsWith("how")) {
if (message.contains("first")) {
firstCount++;
}
else if (message.contains("second")) {
secondCount++;
}
else {
System.out.println(message);
}
}
else {
successCount++;
}
}
System.out.printf("Stats: %d successful, %d detected first, %d detected second", successCount, firstCount, secondCount);
}
Which prints something like:
Stats: 85 successful, 5 detected first, 10 detected second
I am using #RabbitListner annotation to recieve messages from a RabbitMq queue.
How to make threads receive messages no more often than 1 second?
#RabbitListener(queues = "message", priority = "3",concurrency = "2")
public void receiveCheck(RequestMessage message){
}
Your task is a bit strange. Don't you think that the problem should be solved differently (maybe you can send messages with a certain frequency - 1 message/sec)?
But if you're sure that's what you need, you could use primitive solution:
#RabbitListener(queues = "message", priority = "3", concurrency = "2")
public void receiveMessage(String message) throws InterruptedException {
System.out.println("Received <" + message + ">" + " Message time: " + LocalDateTime.now());
Thread.sleep(1000);
}
Or with the calculation of the operation time:
#RabbitListener(queues = "message", priority = "3", concurrency = "2")
public void receiveMessageWithTimer(String message) throws InterruptedException {
long start = System.currentTimeMillis();
System.out.println("Received <" + message + ">" + " Message time: " + LocalDateTime.now());
long finish = System.currentTimeMillis();
long operationTime = finish - start;
Thread.sleep(1000 - operationTime);
}
But in this case you should remeber that concurrency level = 2. And you will receive 2 message/sec.
For receiving of only one message you could set concurrency level = 1.
I am threading a time consuming for-loop and executing them inside N number of threads. A continue statement is throwing error
Getting the error "Continue cannot be used outside of a loop"
for (final Message m : messagelistholder.getMessage()) {
Callable<Void> tasksToExecute = new Callable<Void>() {
public Void call() {
if (guidanceonly1 == true && !QuoteUtil.isECPQuote(list.get(0))) {
String msg = "Message From " + m.getSource() + " when retrieving Guidance values: "
+ m.getDescription();
String lcladdStatusMessages = CommonUtil.getLoclizedMsg(
"PRCE_LNE_ITM_MSG_FRM_WHN_RETRVNG_GUIDNCE_VAL",
new String[]{m.getSource(), m.getDescription()}, msg);
list.get(0).addStatusMessages("Info", lcladdStatusMessages);
} else if ("Error".equalsIgnoreCase(m.getSeverity())) {
if (m.getCode().indexOf("_NF") > 0) {
continue; // price not found due to private sku
}
if ("Eclipse".equalsIgnoreCase(m.getSource())) {
String msg1 = "Please check Sold To customer data. ";
String lcladdStatusMessages1 = CommonUtil
.getLoclizedMsg("PRCE_LNE_ITM_PLS_CHK_SLDTO_CUST_DTA", null, msg1);
String msg2 = "Discount information may not be returned from Optimus due to "
+ m.getSeverity() + " From " + m.getSource() + " " + m.getDescription();
String lcladdStatusMessages2 = CommonUtil.getLoclizedMsg(
"PRCE_LNE_ITM_DSCNT_INFO_MNT_RTRND_FRM_OPTMS_DUETO_FRM",
new String[]{m.getSeverity(), m.getSource(), m.getDescription()}, msg2);
list.get(0).addStatusMessages(m.getSeverity(),
(m.getDescription().contains("MDCP") ? lcladdStatusMessages1 : "")
+ lcladdStatusMessages2);
} else {
if (response1.getItems() == null) {
String lcladdStatusMessages = CommonUtil.getLoclizedMsg("PRCE_LNE_ITM_OPTMS_ERR",
new String[]{m.getSource(), m.getDescription()}, m.getDescription());
list.get(0).addStatusMessages("Error", lcladdStatusMessages);
list.get(0).setOptimusError(true);
} else {
if (!QuoteUtil.isECPQuote(list.get(0))) {
String lcladdStatusMessages = CommonUtil.getLoclizedMsg(
"PRCE_LNE_ITM_MSG_FRM_WHN_RETRVNG_GUIDNCE_VAL",
new String[]{m.getSource(), m.getDescription()},
"Message From " + m.getSource() + " " + m.getDescription());
list.get(0).addStatusMessages("Info", lcladdStatusMessages);
list.get(0).setOptimusError(true);
}
}
}
}
if (list.get(0).getFlags().get(QtFlagType.ESCALATIONFORPARTNER) != null) {
list.get(0).getFlags().get(QtFlagType.ESCALATIONFORPARTNER).setFlgVl(null);
}
if (m.getCode() != null) {
String pricingServiceMsgCode = m.getCode();
String pricingServiceSeverity = m.getSeverity();
Map<Integer, AutoEscalationScenario> categoryMap;
if (StringUtils.equals("ERROR", pricingServiceSeverity)) {
categoryMap = getScenario("SEVERITY", globalAccount1, null, true, null);
if (categoryMap.size() != 0) {
finalCategorylist.get(0).putAll(categoryMap);
}
}
if (partnerExclusivityAutoEscalation1) {
categoryMap = getScenario(pricingServiceMsgCode, globalAccount1, null, true, null);
if (categoryMap != null && categoryMap.size() != 0) {
finalCategorylist.get(0).putAll(categoryMap);
}
}
}
return null;
}
};
runnableTasks.add(tasksToExecute);
}
Can someone help me to skip the particular loop for the speicified condition but without using continue statement since it throws error.
What's happening is that you are actually calling continue outside of a loop because the call() function itself does not have a for loop, so it doesn't matter if are only calling call() from a loop.
What can you do to fix this is making the call function to return a boolean and replacing the continues with return true and return false if no return true has been reached.
Then replace the:
call()
on the loop(s) for
if(call()) continue
So the I'm not saying I fully understand you code, but it appears that you are using continue to break out of that thread. On a normal multi-threaded application, it looks like you are launching multiple threads from one one loop. The continue call is inside the new thread, not the loop. As soon as you start writing the call() method, you leave the loop to run it. Looking at the code, I would try replacing continue with return. Normally I would try running it myself before I suggest it, but without the rest of the code I cannot verify that it works.
I need to test this code with Mockito (JUnit):
public class Calculation {
public void logTimeTaken(String label, long estimatedTime, int size, boolean isDebug) {
String out = label + " took " + TimeUnit.MILLISECONDS.convert(estimatedTime, TimeUnit.NANOSECONDS) + " milliseconds for " + size + " events!";
if (isDebug) {
System.out.println(out);
} else {
System.out.println(out);
}
}
}
I search so many examples google but still not getting any idea.
You can configure System with an instance of PrintStream which you can then assert against after invoking Calculation.logTimeTaken.
Here's an example:
#Test
public void canLogTimeTaken() {
ByteArrayOutputStream bout = new ByteArrayOutputStream();
PrintStream out = new PrintStream(bout);
System.setOut(out);
Calculation sut = new Calculation();
sut.logTimeTaken("label", 20 , 2, false);
assertEquals("if isDebug is false label took 0 milliseconds for 2 events!\n", bout.toString());
}
Note: there is no need for Mockito here, this is just vanilla JUnit, no mocking.
But, it might be a better design to refactor logTimeTaken into two distinct aspects:
Deriving the log message
Logging that message
For example:
public String createTimeTakenMessage(String label, long estimatedTime, int size, boolean isDebug) {
return label + " took " + TimeUnit.MILLISECONDS.convert(estimatedTime, TimeUnit.NANOSECONDS) + " milliseconds for " + size + " events!";
}
public void logTimeTaken(String message) {
System.out.println(message);
}
Then testing createTimeTakenMessage is trivial and you might even choose not to test logTimeTaken at all since all it does is invoke a System method. Or, perhaps you would hide the 'log action' behind an interface with an implementation using System.out now and perhaps, later, other implementations using a formal logging framework such as Logback.
I am making a ping program using Java sockets. One bug in my program is that sometimes it will not connect and will just sit there for ever. So I am trying to add a timeout (after twenty seconds) and the ping will fail. But I have no idea how to.
Here is part of my ping program:
boolean result = false;
long before1 = System.nanoTime();
out.println(new byte[64]);
System.out.println("(1) Sent 64 bytes of data to " + address
+ "...");
try {
if ((in.readLine()) != null) {
int size = in.readLine().toString().getBytes().length;
long after = System.nanoTime();
long s = ((after - before1) / 1000000L) / 1000;
System.out.println("(1) Recieved reply from " + address
+ " (" + size + " bytes), time = " + s
+ " seconds...");
result = true;
} else if ((in.readLine()) == null) {
long after = System.nanoTime();
long s = ((after - before1) / 1000000L) / 1000;
System.out.println("(1) Failed to recieve reply from "
+ address + ", time = " + s + " seconds...");
result = false;
}
} catch (IOException exc) {
long after = System.nanoTime();
long s = ((after - before1) / 1000000L) / 1000;
System.err.println("(1) Failed to recieve reply from "
+ address + ", time = " + s + " seconds...\nReason: "
+ exc);
result = false;
}
But I would like to measure time elapsed any where in my code, instead of:
long time = System.nanoTime();
If one part of my code is stuck doing something it will time out after 20 seconds.
Any suggestions on how to measure if twenty seconds has passed at the start of a try/catch block or anywhere else in my code so it doesn't get stuck during the ping?
As "jsn" and "jahory" said you need to do this with threads. Here's 2 useful links, you can check them ;)
How to implement timeout using threads
Adding a thread timeout to methods in Java
You can use Future and FutureTask:
ExecutorService pingExecutor = ... // executor service to run the ping in other thread
void showPing(final String target) throws InterruptedException {
Future<String> ping = executor.submit(new Callable<String>() {
public String call() {
String pingResult = ... // do your Ping stuff
return pingResult;
}});
System.out.println("Pinging..."); // do other things while searching
try {
System.out.println(future.get(20, TimeUnit.SECONDS)); // use future, waits 20 seconds for the task to complete
} catch (ExecutionException ex) {
} catch (TimeoutException tex) {
// Ping timed out
}
}
You can find some hints here: How do I call some blocking method with a timeout in Java?
Future interface looks like a good solution to your problem. Remember, however, that depending on what your task is doing, you probably would be not able to really cancel it. Additional info:
tutorial (see, in particular, Non-blocking algorithms section)