Spring MVC blocking queue with initializing of huge library - java
I am using a huge library in my application. I cannot initialize the library every time a request come so I put the initialization into the configuration. I have implemented a queue and a service for managing the queue. After application is loaded I have two instances running. Problem is that it stucks and no response is getting back.
Application context xml:
<context:component-scan base-package="com.metadata.tripletws.model" />
<context:component-scan base-package="com.metadata.tripletws.service" />
<bean id="wsdService" class="com.metadata.tripletws.service.WsdService" init-method="init"></bean>
<context:component-scan base-package="com.metadata.tripletws.controller" />
Service
#Service
public class WsdService
{
public final static int MAX_THREADS = 2;
private WsdQueue queue;
public void init()
{
try {
queue = new WsdQueue(MAX_THREADS);
queue.initQueue();
} catch (InterruptedException ex) {
Logger.getLogger(WsdService.class.getName()).log(Level.SEVERE, null, ex);
}
}
public WSD getInstance() throws InterruptedException
{
return queue.dequeue();
}
public void releaseInstance(WSD instance) throws InterruptedException
{
queue.enqueue(instance);
}
}
Queue
public class WsdQueue
{
private List<WSD> queue = new LinkedList();
private int limit = 5;
public WsdQueue()
{
}
public WsdQueue(int limit)
{
this.limit = limit;
}
public void initQueue() throws InterruptedException
{
for (int i = 0; i < limit; i++) {
System.out.println("Initializing WSD nr." + i);
WSD wsd = new WSD();
wsd.Initialize();
this.enqueue(wsd);
}
}
public synchronized void enqueue(WSD item) throws InterruptedException
{
while (this.queue.size() == this.limit) {
wait();
}
if (this.queue.size() == 0) {
notifyAll();
}
System.out.println("Adding instance");
this.queue.add(item);
}
public synchronized WSD dequeue() throws InterruptedException
{
while (this.queue.size() == 0) {
wait();
}
if (this.queue.size() == this.limit) {
notifyAll();
}
System.out.println("Taking instance");
return this.queue.remove(0);
}
}
and here is the controller
Controller
#RequestMapping(value = "/api")
public class ApiController
{
#Autowired
private WsdService wsdService;
#RequestMapping(value = "/wordnet", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
public #ResponseBody
ArrayList<LexicalWord> getWordsFromSentence(#RequestBody String sentence)
{
ArrayList<LexicalWord> results = new ArrayList<>();
try {
WSD wsdInstance = wsdService.getInstance();
List<CWSDResult> list = wsdInstance.AnanlyseSentenceToList(sentence);
for (CWSDResult res : list) {
if (!res.hasLegalSense) {
continue;
}
String key = getHighestProbableSynsetKey(res);
if (key != null && res.senses.containsKey(key)) {
Synset synset = res.senses.get(key);
if (synset != null) {
results.add(new LexicalWord(res.token, synset.getLexFileName()));
}
}
}
wsdService.releaseInstance(wsdInstance);
} catch (InterruptedException ex) {
Logger.getLogger(ApiController.class.getName()).log(Level.SEVERE, null, ex);
}
return results;
}
}
This is the first time I am making a queue and working with threads and I appriciate any kind of help or example. There is no error, it just stucks, does nothing and no response is send back.
EDIT1:
after answers I changed the code, but no luck. Still stucks. Maybe the problem is somewhere else, but when I send a single request it works and I get the response.
#Component
public class WsdService
{
public final static int MAX_THREADS = 2;
private BlockingQueue<WSD> queue;
public WsdService()
{
queue = new ArrayBlockingQueue(MAX_THREADS);
}
#PostConstruct
public void init()
{
try {
for (int i = 0; i < MAX_THREADS; i++) {
WSD wsd = new WSD();
wsd.Initialize();
System.out.println("WSD nr. " + i + " initialized!");
queue.put(wsd);
}
} catch (InterruptedException ex) {
Logger.getLogger(WsdService.class.getName()).log(Level.SEVERE, null, ex);
}
}
public WSD getInstance() throws InterruptedException
{
return queue.take();
}
public void releaseInstance(WSD instance) throws InterruptedException
{
queue.put(instance);
}
}
and here is new applicationContext
<context:component-scan base-package="com.metadata.tripletws.model" />
<context:component-scan base-package="com.metadata.tripletws.service" />
<context:component-scan base-package="com.metadata.tripletws.controller" />
SOLUTION
So ..after lot of digging of the library I assumed it is not possible to use multithreading there. Anyway I used the blockingQueue in other service (NLP) and it is working nicely (Same as EDIT1 just the variable is different). Thanks everybody for your help.
Thanks,
Michal
So you're essentially trying to make a pool of WSDs?. You're certain that WSD isn't thread-safe?
You can safely throw your queue in the garbage, and use a correct ready made version of BlockingQueue instead. It might not necessarily solve your actual problem, but it'll be a working version of what you're attempting here.
Related
Spring Batch - Not Shutting down - Due to Static Method call
I have completed a spring batch (Standalone Jar) in Spring Boot + CommandLineRunner. But the JVM is not getting shutdown after completion. After doing some research initially I thought its not shutting down because of below reasons. 1 . I am not closing the spring application context at the end ofcommandline runner. 2 . Executor service is not shutdown properly which might have caused the JVM from shutting down. I dont want to call system.exit which is a forceful shutdown. I tried closing the application context and also verified executor service is shutdown using isShutdown method (returns true). Then I found out the root cause, it is because I am calling a static method which is the culprit. When I commented the static method call, the job was shutting down gracefully even if I dont close the application context explicitly. I am not sure why this behavior and do I need to convert everything to objects or is there something else I am missing here. Can someone please throw some light. Main Class #SpringBootApplication #ComponentScan(basePackages = "com.acn.abp.printbatch") #EnableTransactionManagement #ImportResource({ "ABPBatchInfrastructure.xml", "financeBillPayAppConfig.xml" }) public class financeBillPayFileUploadApplication extends PrintBatchConstants implements CommandLineRunner { #Autowired private NotifyConfig notify; #Autowired private ApplicationContext ctx; static final Logger logger = LoggerFactory.getLogger(financeBillPayFileUploadApplication.class); public static void main(String[] args) { SpringApplication application = new SpringApplication(financeBillPayFileUploadApplication.class); application.setBannerMode(Banner.Mode.OFF); application.run(args); } #Override public void run(String... args) throws Exception { logger.info(notify.getEnvironment()); JobLauncher jobLauncher = ctx.getBean(JobLauncher.class); Job job = ctx.getBean(Job.class); jobLauncher.run(job, new JobParametersBuilder() .addString(batchDocumentClass, "InvoiceStatementDocumentation") .addString(batchType, "2020-06-04") .addString(batchEmailID, notify.getSupportEmailId()) .addString(batchEnvironment, notify.getEnvironment()) .toJobParameters()); System.out.println("Here cxf"); ((ConfigurableApplicationContext)ctx).close(); } } Below Class which is causing the problem. If I comment out below code then everything works perfectly. populateItemDocuments(job, printConfig.geteCMObjectStore(), printConfig.geteCMUserId()); Class file where this method is called #Component public class DuplexWorker implements Callable { static final Logger logger = LoggerFactory.getLogger(DuplexWorker.class); #Autowired private ManageFormService formgmtClient; #Autowired private PostScriptService postScriptService; #Autowired private BarcodeService barcodeService; private static CfBatchPrintConfiguration printConfig; private static CfPersistenceUtil dbUtilService; private static FilenetDocumentRetrieval docmgmtClient; #Autowired public DuplexWorker(CfPersistenceUtil dbUtilService,CfBatchPrintConfiguration printConfig,FilenetDocumentRetrieval docmgmtClient) { DuplexWorker.dbUtilService = dbUtilService; DuplexWorker.printConfig = printConfig; DuplexWorker.docmgmtClient=docmgmtClient; } private MailUtil mailUtil; private NotifyConfig notify; private List<PrintJobItem> printJobItems; private List<String> groupIds; private ArrayList duplexJobs; private String groupId; private CountDownLatch latch; public DuplexWorker(ArrayList duplexJobs, String groupId,CountDownLatch latch) { super(); this.latch=latch; this.duplexJobs = duplexJobs; this.groupId = groupId; } public DuplexWorker(CountDownLatch latch, MailUtil mailUtil,NotifyConfig notify,List<PrintJobItem> findByPrintStatusEquals,List<String>groupIds) { this.latch=latch; this.mailUtil=mailUtil; this.notify=notify; this.printJobItems=findByPrintStatusEquals; this.groupIds=groupIds; } #Override public Object call() throws Exception { try { if ((duplexJobs != null) && (!duplexJobs.isEmpty())) { String prevJobId = null; int docCount = 0; CvPrintJob consolidatedPrintJob = (CvPrintJob)duplexJobs.get(0); ArrayList printItems = new ArrayList(); if (consolidatedPrintJob != null) { ArrayList items = consolidatedPrintJob.getPrintJobItems(); int numPages = 0; if ((items != null) && (!items.isEmpty())) { CvPrintJobItem firstItem = (CvPrintJobItem)items.get(0); numPages = CfBatchPrintUtil.getItemTotalPages(firstItem); logger.info("Item Total Pages == " + numPages); logger.info("Job Item Page Limit == " + printConfig.getJobItemPageLimit()); consolidatedPrintJob.setSequence(firstItem.getSequence()); } if (numPages <= printConfig.getJobItemPageLimit()) { consolidatedPrintJob.setHasLargeItems(false); logger.info("Item setHasLargeItems == false"); } else { consolidatedPrintJob.setHasLargeItems(true); logger.info("Item setHasLargeItems == true"); } } ArrayList startBannerDataList = new ArrayList(); ArrayList barcodeList = new ArrayList(); ArrayList barcodeCorresPageCount = new ArrayList(); ArrayList statementNumberList = new ArrayList(); for (int i = 0; i < duplexJobs.size(); i++) { CvPrintJob job = (CvPrintJob)duplexJobs.get(i); if ((prevJobId == null) || (!prevJobId.equalsIgnoreCase(job.getJobId()))) { docCount = 0; } populateItemDocuments(job, printConfig.geteCMObjectStore(), printConfig.geteCMUserId()); } consolidatedPrintJob.setPrintJobItems(printItems); } else { logger.info("===================================================================="); logger.info("=================>> No DUPLEX jobs to process <<==================="); logger.info("===================================================================="); } duplexJobs = null; this.latch.countDown(); System.gc(); return null; }catch(Exception e) { e.printStackTrace(); return null; } } public static void populateItemDocuments(CvPrintJob job, String objectStore, String userid) throws CfException { logger.info("Enters populateItemDocuments"); try { ArrayList items = job.getPrintJobItems(); job.setIsProcess(true); ArrayList modelDocList = null; logger.info("Items size::::::" + items.size()); for (int i = 0; i < items.size(); i++) { modelDocList = new ArrayList(); CvPrintJobItem x = (CvPrintJobItem)items.get(i); ArrayList guidList = x.getGuidList(); if ((guidList != null) && (!guidList.isEmpty())) { modelDocList.addAll(guidList); } logger.info("guidList size::::::" + guidList.size()); CvRenderPayloadRequest cvRenderPayloadRequest = null; if ((modelDocList != null) && (!modelDocList.isEmpty())) { cvRenderPayloadRequest = new CvRenderPayloadRequest(); logger.info("Before creating CvRenderPayloadRequest"); logger.info("Document Class::: " + x.getDocumentClass()); cvRenderPayloadRequest.setDocumentClass( x.getDocumentClass()); cvRenderPayloadRequest.setGuid(modelDocList); cvRenderPayloadRequest.setUserId(userid); logger.info("After creating the CvRenderPayloadRequest"); try { if (cvRenderPayloadRequest != null) { List pdfContents = docmgmtClient.retrieveDocument(cvRenderPayloadRequest.getGuid()); if ((pdfContents != null) && (!pdfContents.isEmpty())) { logger.info( "PDF contents sizenew::::::::::::::" + pdfContents.size()); Iterator pdfItr = pdfContents.iterator(); while (pdfItr.hasNext()) { byte[] contents = (byte[])pdfItr.next(); CvPrintJobItem item = (CvPrintJobItem)items.get(i); item.addDocumentList(contents); int filenetpagecount = 100; item.setPageCountFromFileNet(filenetpagecount); logger.info("PageCOunt from Filenet " + filenetpagecount); } } } } catch (Exception e) { e.printStackTrace(); throw new CfException(" Error populating documents" + e); } } } } catch (Exception e) { e.printStackTrace(); throw new CfException(" Error populating documents" + e); } logger.info("Exits populateItemDocuments"); }
First of all you are using Tomcat server that runs the application. If you want to make standalone spring application you can configure like below #Configuration public class ApplicationMain { #Bean public Stackoverflow stackoverflow() { return new Stackoverflow (); } public static void main(String[] args) { ConfigurableApplicationContext configurableApplicationContext = new AnnotationConfigApplicationContext(ApplicationMain.class); System.out.println(configurableApplicationContext.getBean("stackoverflow")); } } 'JVM is not getting shutdown after completion.' is normal behavior for Tomcat server because it waits for request to handle. You can give basepackage like below new AnnotationConfigApplicationContext("com.example"); it will scan the package for you
Spring WebFlux consumer to sink
Here is a simple spring boot application: #SpringBootApplication #RestController public class ReactiveApplication { static Flux<String> fluxString; static volatile Queue<String> queue = new ConcurrentLinkedQueueProxy(); private static class ConcurrentLinkedQueueProxy extends ConcurrentLinkedQueue<String> { private static final long serialVersionUID = 1L; #Override public boolean add(String e) { synchronized (this) { notify(); } return super.add(e); } #Override public String poll() { synchronized (this) { if(isEmpty()) { try { wait(); } catch (InterruptedException ex) {} } } return super.peek() == null ? "" : super.poll(); } } static Consumer<String> consumer = str -> queue.add(str); public static void main(String[] args) throws InterruptedException { SpringApplication.run(ReactiveApplication.class, args); } static { for(int i = 0; i < 10; i++) queue.add("testData " + i + " "); } #GetMapping(value = "/", produces = MediaType.APPLICATION_STREAM_JSON_VALUE) public Flux<String> home() { Scheduler sch = Schedulers.newParallel("parallel-sch", 1); List<String> list = new ArrayList<>(queue); queue.removeAll(queue); fluxString = Flux.<String>create(sink -> { sink.onRequest(n -> { for(int i = 0; i < n; i++) { sink.next(queue.poll()); } }).onCancel(() -> sch.dispose()); }).log().subscribeOn(sch).mergeWith(Flux.<String>fromIterable(list)); return fluxString; } #GetMapping("/add") public String add( #RequestParam String s) { consumer.accept(s); return s; } } So basically this application creates a String stream. Visiting / will grab all the string present queue and then merge anything that is added from /add resource(ignore the "Safe Methods Must be Idempotent" thing). What I feel is strange is that when I move public static void main(...) to line 1, the application starts to misbehave and adding new values to /add doesn't have any effect. I think there must be something interesting going on that is making application misbehave. Any explaination?
I ended up using this which works great: #SpringBootApplication #RestController public class ReactiveApplication { private static BlockingQueue<String> queue = new ArrayBlockingQueue<>(1000); private static Consumer<String> consumer = str -> { try { queue.put(str); } catch (InterruptedException e) {} }; static { for (int i = 0; i < 10; i++) queue.add("testData " + i + " "); } public static void main(String[] args) { SpringApplication.run(ReactiveApplication.class, args); } #GetMapping(value = "/", produces = MediaType.APPLICATION_STREAM_JSON_VALUE) public Flux<String> home() { final Scheduler sch = Schedulers.newSingle("async-flux"); return Flux.<String>generate(sink -> { try { sink.next(queue.take()); } catch (InterruptedException e) { } }).log().subscribeOn(sch); } #GetMapping("/add") public String add(#RequestParam String s) { consumer.accept(s); return s; } }
Spring AOP logging thread method
Is there any way to implement AOP logging to public method of class that implements Runnable and ran by ExecutorService? Thread class #Component #Scope("prototype") public class FileProcessor implements Runnable { private final LinkedBlockingQueue<File> filesQueue; private final GiftCertificateMapper certificateMapper; private final File errorFolder; private static final ReentrantLock LOCK = new ReentrantLock(); private static final Logger LOGGER = LoggerFactory.getLogger(FileProcessor.class); public FileProcessor(LinkedBlockingQueue<File> filesQueue, GiftCertificateMapper certificateMapper, File errorFolder) { this.filesQueue = filesQueue; this.certificateMapper = certificateMapper; this.errorFolder = errorFolder; } #Override public void run() { File file = null; try { while ((file = filesQueue.poll(100, TimeUnit.MILLISECONDS)) != null) { processFile(file); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); LOGGER.warn("File thread was interrupted"); } catch (IOException e) { LOGGER.error("Error processing file {} \n{}", file.getAbsolutePath(), e); } } public void processFile(File file) throws IOException { if (file != null) { try { ObjectMapper objectMapper = new ObjectMapper(); List<GiftCertificate> certificates = Arrays.asList(objectMapper.readValue(file, GiftCertificate[].class)); certificateMapper.insertList(certificates); file.delete(); } catch (JsonParseException | UnrecognizedPropertyException | InvalidFormatException | DataIntegrityViolationException e) { moveFileToErrorFolder(file); } } } private void moveFileToErrorFolder(File file) throws IOException { try { LOCK.lock(); Files.move(Paths.get(file.getAbsolutePath()), getPathForMovingFile(file), StandardCopyOption.ATOMIC_MOVE); } finally { LOCK.unlock(); } } private Path getPathForMovingFile(File fileForMove) { File fileList[] = errorFolder.listFiles(); int filesWithSameNameCounter = 0; if (fileList != null && fileList.length > 0) { for (File file : fileList) { if (file.getName().contains(fileForMove.getName())) { filesWithSameNameCounter++; } } } return filesWithSameNameCounter > 0 ? Paths.get(errorFolder.getAbsolutePath(), "(" + filesWithSameNameCounter + ")" + fileForMove.getName()) : Paths.get(errorFolder.getAbsolutePath(), fileForMove.getName()); } } Aspect #Aspect #Component #ConditionalOnProperty( value = "file-processing.logging.enabled", havingValue = "true", matchIfMissing = true) public class FileProcessingLoggingAspect { private static final Logger LOGGER = LoggerFactory.getLogger(FileProcessingLoggingAspect.class); #Pointcut("execution(* com.epam.esm.processor.FileProcessor.processFile(java.io.File))") public void processFilePointcut() { } #Around("processFilePointcut()") public Object logFileProcessing(ProceedingJoinPoint joinPoint) throws Throwable { // File file = (File) joinPoint.getArgs()[0]; // long time = System.currentTimeMillis(); Object object = joinPoint.proceed(); // long resultTime = System.currentTimeMillis() - time; LOGGER.info("Processing of file took milliseconds"); return object; } }
In Spring AOP , internal method calls cannot be intercepted. In the code shared , even though the method processFile() is public , it gets called from run(). This is a self reference / internal method call , which cannot be intercepted. Details can be read in the documentation Due to the proxy-based nature of Spring’s AOP framework, calls within the target object are, by definition, not intercepted. For JDK proxies, only public interface method calls on the proxy can be intercepted A pointcut expression to intercept all external method calls to a class implementing Runnable would be as follows #Around("this(java.lang.Runnable) && within(com.epam.esm.processor..*)") public Object logFileProcessing(ProceedingJoinPoint pjp) throws Throwable { try { return pjp.proceed(); } finally { //log System.out.println("****Logged"); } } Scoping designator within() limits the scope to apply the advice. The point cut #Pointcut("execution(* com.epam.esm.processor.FileProcessor.processFile(java.io.File))") is valid and would work if an external method call happens to it. Hope this helps.
How do you implement a re-try-catch?
Try-catch is meant to help in the exception handling. This means somehow that it will help our system to be more robust: try to recover from an unexpected event. We suspect something might happen when executing and instruction (sending a message), so it gets enclosed in the try. If that something nearly unexpected happens, we can do something: we write the catch. I don't think we called to just log the exception. I thing the catch block is meant to give us the opportunity of recovering from the error. Now, let's say we recover from the error because we could fix what was wrong. It could be super nice to do a re-try: try{ some_instruction(); } catch (NearlyUnexpectedException e){ fix_the_problem(); retry; } This would quickly fall in the eternal loop, but let's say that the fix_the_problem returns true, then we retry. Given that there is no such thing in Java, how would YOU solve this problem? What would be your best design code for solving this? This is like a philosophical question, given that I already know what I'm asking for is not directly supported by Java.
You need to enclose your try-catch inside a while loop like this: - int count = 0; int maxTries = 3; while(true) { try { // Some Code // break out of loop, or return, on success } catch (SomeException e) { // handle exception if (++count == maxTries) throw e; } } I have taken count and maxTries to avoid running into an infinite loop, in case the exception keeps on occurring in your try block.
Obligatory "enterprisy" solution: public abstract class Operation { abstract public void doIt(); public void handleException(Exception cause) { //default impl: do nothing, log the exception, etc. } } public class OperationHelper { public static void doWithRetry(int maxAttempts, Operation operation) { for (int count = 0; count < maxAttempts; count++) { try { operation.doIt(); count = maxAttempts; //don't retry } catch (Exception e) { operation.handleException(e); } } } } And to call: OperationHelper.doWithRetry(5, new Operation() { #Override public void doIt() { //do some stuff } #Override public void handleException(Exception cause) { //recover from the Exception } });
As usual, the best design depends on the particular circumstances. Usually though, I write something like: for (int retries = 0;; retries++) { try { return doSomething(); } catch (SomeException e) { if (retries < 6) { continue; } else { throw e; } } }
You can use AOP and Java annotations from jcabi-aspects (I'm a developer): #RetryOnFailure(attempts = 3, delay = 5) public String load(URL url) { return url.openConnection().getContent(); } You could also use #Loggable and #LogException annotations.
Although try/catch into while is well-known and good strategy I want to suggest you recursive call: void retry(int i, int limit) { try { } catch (SomeException e) { // handle exception if (i >= limit) { throw e; // variant: wrap the exception, e.g. throw new RuntimeException(e); } retry(i++, limit); } }
Spring AOP and annotation based solution: Usage (#RetryOperation is our custom annotation for the job): #RetryOperation(retryCount = 1, waitSeconds = 10) boolean someMethod() throws Exception { } We'll need two things to accomplish this: 1. an annotation interface, and 2. a spring aspect. Here's one way to implement these: The Annotation Interface: import java.lang.annotation.*; #Target(ElementType.METHOD) #Retention(RetentionPolicy.RUNTIME) public #interface RetryOperation { int retryCount(); int waitSeconds(); } The Spring Aspect: import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.reflect.MethodSignature; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import java.lang.reflect.Method; #Aspect #Component public class RetryAspect { private static final Logger LOGGER = LoggerFactory.getLogger(RetryAspect.class); #Around(value = "#annotation(RetryOperation)") public Object retryOperation(ProceedingJoinPoint joinPoint) throws Throwable { Object response = null; Method method = ((MethodSignature) joinPoint.getSignature()).getMethod(); RetryOperation annotation = method.getAnnotation(RetryOperation.class); int retryCount = annotation.retryCount(); int waitSeconds = annotation.waitSeconds(); boolean successful = false; do { try { response = joinPoint.proceed(); successful = true; } catch (Exception ex) { LOGGER.info("Operation failed, retries remaining: {}", retryCount); retryCount--; if (retryCount < 0) { throw ex; } if (waitSeconds > 0) { LOGGER.info("Waiting for {} second(s) before next retry", waitSeconds); Thread.sleep(waitSeconds * 1000l); } } } while (!successful); return response; } }
Most of these answers are essentially the same. Mine is also, but this is the form I like boolean completed = false; Throwable lastException = null; for (int tryCount=0; tryCount < config.MAX_SOME_OPERATION_RETRIES; tryCount++) { try { completed = some_operation(); break; } catch (UnlikelyException e) { lastException = e; fix_the_problem(); } } if (!completed) { reportError(lastException); }
Use a while loop with local status flag. Initialize the flag as false and set it to true when operation is successful e.g. below: boolean success = false; while(!success){ try{ some_instruction(); success = true; } catch (NearlyUnexpectedException e){ fix_the_problem(); } } This will keep retrying until its successful. If you want to retry only certain number of times then use a counter as well: boolean success = false; int count = 0, MAX_TRIES = 10; while(!success && count++ < MAX_TRIES){ try{ some_instruction(); success = true; } catch (NearlyUnexpectedException e){ fix_the_problem(); } } if(!success){ //It wasn't successful after 10 retries } This will try max 10 times if not successful until then an will exit if its successful before hand.
This is an old question but a solution is still relevant. Here is my generic solution in Java 8 without using any third party library: public interface RetryConsumer<T> { T evaluate() throws Throwable; } public interface RetryPredicate<T> { boolean shouldRetry(T t); } public class RetryOperation<T> { private RetryConsumer<T> retryConsumer; private int noOfRetry; private int delayInterval; private TimeUnit timeUnit; private RetryPredicate<T> retryPredicate; private List<Class<? extends Throwable>> exceptionList; public static class OperationBuilder<T> { private RetryConsumer<T> iRetryConsumer; private int iNoOfRetry; private int iDelayInterval; private TimeUnit iTimeUnit; private RetryPredicate<T> iRetryPredicate; private Class<? extends Throwable>[] exceptionClasses; private OperationBuilder() { } public OperationBuilder<T> retryConsumer(final RetryConsumer<T> retryConsumer) { this.iRetryConsumer = retryConsumer; return this; } public OperationBuilder<T> noOfRetry(final int noOfRetry) { this.iNoOfRetry = noOfRetry; return this; } public OperationBuilder<T> delayInterval(final int delayInterval, final TimeUnit timeUnit) { this.iDelayInterval = delayInterval; this.iTimeUnit = timeUnit; return this; } public OperationBuilder<T> retryPredicate(final RetryPredicate<T> retryPredicate) { this.iRetryPredicate = retryPredicate; return this; } #SafeVarargs public final OperationBuilder<T> retryOn(final Class<? extends Throwable>... exceptionClasses) { this.exceptionClasses = exceptionClasses; return this; } public RetryOperation<T> build() { if (Objects.isNull(iRetryConsumer)) { throw new RuntimeException("'#retryConsumer:RetryConsumer<T>' not set"); } List<Class<? extends Throwable>> exceptionList = new ArrayList<>(); if (Objects.nonNull(exceptionClasses) && exceptionClasses.length > 0) { exceptionList = Arrays.asList(exceptionClasses); } iNoOfRetry = iNoOfRetry == 0 ? 1 : 0; iTimeUnit = Objects.isNull(iTimeUnit) ? TimeUnit.MILLISECONDS : iTimeUnit; return new RetryOperation<>(iRetryConsumer, iNoOfRetry, iDelayInterval, iTimeUnit, iRetryPredicate, exceptionList); } } public static <T> OperationBuilder<T> newBuilder() { return new OperationBuilder<>(); } private RetryOperation(RetryConsumer<T> retryConsumer, int noOfRetry, int delayInterval, TimeUnit timeUnit, RetryPredicate<T> retryPredicate, List<Class<? extends Throwable>> exceptionList) { this.retryConsumer = retryConsumer; this.noOfRetry = noOfRetry; this.delayInterval = delayInterval; this.timeUnit = timeUnit; this.retryPredicate = retryPredicate; this.exceptionList = exceptionList; } public T retry() throws Throwable { T result = null; int retries = 0; while (retries < noOfRetry) { try { result = retryConsumer.evaluate(); if (Objects.nonNull(retryPredicate)) { boolean shouldItRetry = retryPredicate.shouldRetry(result); if (shouldItRetry) { retries = increaseRetryCountAndSleep(retries); } else { return result; } } else { // no retry condition defined, no exception thrown. This is the desired result. return result; } } catch (Throwable e) { retries = handleException(retries, e); } } return result; } private int handleException(int retries, Throwable e) throws Throwable { if (exceptionList.contains(e.getClass()) || (exceptionList.isEmpty())) { // exception is excepted, continue retry. retries = increaseRetryCountAndSleep(retries); if (retries == noOfRetry) { // evaluation is throwing exception, no more retry left. Throw it. throw e; } } else { // unexpected exception, no retry required. Throw it. throw e; } return retries; } private int increaseRetryCountAndSleep(int retries) { retries++; if (retries < noOfRetry && delayInterval > 0) { try { timeUnit.sleep(delayInterval); } catch (InterruptedException ignore) { Thread.currentThread().interrupt(); } } return retries; } } Let's have a test case like: #Test public void withPredicateAndException() { AtomicInteger integer = new AtomicInteger(); try { Integer result = RetryOperation.<Integer>newBuilder() .retryConsumer(() -> { int i = integer.incrementAndGet(); if (i % 2 == 1) { throw new NumberFormatException("Very odd exception"); } else { return i; } }) .noOfRetry(10) .delayInterval(10, TimeUnit.MILLISECONDS) .retryPredicate(value -> value <= 6) .retryOn(NumberFormatException.class, EOFException.class) .build() .retry(); Assert.assertEquals(8, result.intValue()); } catch (Throwable throwable) { Assert.fail(); } }
A simple way to solve the issue would be to wrap the try/catch in a while loop and maintain a count. This way you could prevent an infinite loop by checking a count against some other variable while maintaining a log of your failures. It isn't the most exquisite solution, but it would work.
In case it's useful, a couple more options to consider, all thrown together (stopfile instead of retries, sleep, continue larger loop) all possibly helpful. bigLoop: while(!stopFileExists()) { try { // do work break; } catch (ExpectedExceptionType e) { // could sleep in here, too. // another option would be to "restart" some bigger loop, like continue bigLoop; } // ... more work }
If not all exceptions warrant a retry, only some. And if at least one try has to be made, Here is an alternative utility method: void runWithRetry(Runnable runnable, Class<Exception> exClass, int maxRetries) { Exception err = null; do { maxRetries--; try { runnable.run(); err = null; } catch (Exception e) { if(exClass.isAssignableFrom(e.getClass())){ err = e; }else { throw e; } } } while (err != null && maxRetries > 0); if (err != null) { throw err; } } Usage: runWithRetry(() -> { // do something }, TimeoutException.class, 5)
All a Try-Catch does is allow your program to fail gracefully. In a catch statement, you generally try to log the error, and maybe roll back changes if you need to. bool finished = false; while(finished == false) { try { //your code here finished = true } catch(exception ex) { log.error("there was an error, ex"); } }
Use a do-while to design re-try block. boolean successful = false; int maxTries = 3; do{ try { something(); success = true; } catch(Me ifUCan) { maxTries--; } } while (!successful || maxTries > 0)
Here a reusable and more generic approach for Java 8+ that does not require external libraries: public interface IUnreliable<T extends Exception> { void tryRun ( ) throws T; } public static <T extends Exception> void retry (int retryCount, IUnreliable<T> runnable) throws T { for (int retries = 0;; retries++) { try { runnable.tryRun(); return; } catch (Exception e) { if (retries < retryCount) { continue; } else { throw e; } } } } Usage: #Test public void demo() throws IOException { retry(3, () -> { new File("/tmp/test.txt").createNewFile(); }); }
You can use https://github.com/bnsd55/RetryCatch Example: RetryCatch retryCatchSyncRunnable = new RetryCatch(); retryCatchSyncRunnable // For infinite retry times, just remove this row .retryCount(3) // For retrying on all exceptions, just remove this row .retryOn(ArithmeticException.class, IndexOutOfBoundsException.class) .onSuccess(() -> System.out.println("Success, There is no result because this is a runnable.")) .onRetry((retryCount, e) -> System.out.println("Retry count: " + retryCount + ", Exception message: " + e.getMessage())) .onFailure(e -> System.out.println("Failure: Exception message: " + e.getMessage())) .run(new ExampleRunnable()); Instead of new ExampleRunnable() you can pass your own anonymous function.
Simplifying #ach's previous solution into one file and using functional interfaces. public class OperationHelper { public static void doWithRetry(int maxAttempts, Runnable operation, Consumer<Exception> handle) { for (int count = 0; count < maxAttempts; count++) { try { operation.run(); count = maxAttempts; //don't retry } catch (Exception e) { handle.accept(e); } } } }
simple int MAX = 3; int count = 0; while (true) { try { ... break; } catch (Exception e) { if (count++ < MAX) { continue; } ... break; } }
https://onlinegdb.com/a-7RsL1Gh public void doSomething() throws Exception{ final int MAX_TRIES = 10; int count = 0; while(count++ < MAX_TRIES){ try{ System.out.println("trying"); causeIssue(count); // throws error/exception till count 2 System.out.println("trying successful"); break; // break on success } catch (Exception e){ System.out.println("caught, logging Exception:" + count); } catch (Error e){ System.out.println("caught, logging Error:" + count); } } } Output: trying caught, logging Error:1 trying caught, logging Error:2 trying trying successful
I know there are already many similar answers here, and mine is not much different, but I will post it anyway because it deals with a specific case/issue. When dealing with the facebook Graph API in PHP you sometimes get an error, but immediately re-trying the same thing will give a positive result (for various magical Internet reasons that are beyond the scope of this question). In this case there is no need to fix any error, but to simply try again because there was some kind of "facebook error". This code is used immediately after creating a facebook session: //try more than once because sometimes "facebook error" $attempt = 3; while($attempt-- > 0) { // To validate the session: try { $facebook_session->validate(); $attempt = 0; } catch (Facebook\FacebookRequestException $ex) { // Session not valid, Graph API returned an exception with the reason. if($attempt <= 0){ echo $ex->getMessage(); } } catch (\Exception $ex) { // Graph API returned info, but it may mismatch the current app or have expired. if($attempt <= 0){ echo $ex->getMessage(); } } } Also, by having the for loop count down to zero ($attempt--) it makes it pretty easy to change the number of attempts in the future.
following is my solution with very simple approach! while (true) { try { /// Statement what may cause an error; break; } catch (Exception e) { } }
Im not sure if this is the "Professional" way to do it and i'm not entirely sure if it works for everything. boolean gotError = false; do { try { // Code You're Trying } catch ( FileNotFoundException ex ) { // Exception gotError = true; } } while ( gotError = true );
https://github.com/tusharmndr/retry-function-wrapper/tree/master/src/main/java/io int MAX_RETRY = 3; RetryUtil.<Boolean>retry(MAX_RETRY,() -> { //Function to retry return true; });
The issue with the remaining solutions is that, the correspondent function tries continuously without a time interval in-between, thus over flooding the stack. Why not just trying only every second and ad eternum? Here a solution using setTimeout and a recursive function: (function(){ try{ Run(); //tries for the 1st time, but Run() as function is not yet defined } catch(e){ (function retry(){ setTimeout(function(){ try{ console.log("trying..."); Run(); console.log("success!"); } catch(e){ retry(); //calls recursively } }, 1000); //tries every second }()); } })(); //after 5 seconds, defines Run as a global function var Run; setTimeout(function(){ Run = function(){}; }, 5000); Replace the function Run() by the function or code that you'd like to retry every second.
Give it a try using springs #Retryable annotation , the below method will retry for 3 attempts when RuntimeException occurs #Retryable(maxAttempts=3,value= {RuntimeException.class},backoff = #Backoff(delay = 500)) public void checkSpringRetry(String str) { if(StringUtils.equalsIgnoreCase(str, "R")) { LOGGER.info("Inside retry.....!!"); throw new RuntimeException(); } }
Below snippet execute some code snippet. If you got any error while executing the code snippet, sleep for M milliseconds and retry. Reference link. public void retryAndExecuteErrorProneCode(int noOfTimesToRetry, CodeSnippet codeSnippet, int sleepTimeInMillis) throws InterruptedException { int currentExecutionCount = 0; boolean codeExecuted = false; while (currentExecutionCount < noOfTimesToRetry) { try { codeSnippet.errorProneCode(); System.out.println("Code executed successfully!!!!"); codeExecuted = true; break; } catch (Exception e) { // Retry after 100 milliseconds TimeUnit.MILLISECONDS.sleep(sleepTimeInMillis); System.out.println(e.getMessage()); } finally { currentExecutionCount++; } } if (!codeExecuted) throw new RuntimeException("Can't execute the code within given retries : " + noOfTimesToRetry); }
Here is my solution similar to some others can wrap a function, but allows you to get the functions return value, if it suceeds. /** * Wraps a function with retry logic allowing exceptions to be caught and retires made. * * #param function the function to retry * #param maxRetries maximum number of retires before failing * #param delay time to wait between each retry * #param allowedExceptionTypes exception types where if caught a retry will be performed * #param <V> return type of the function * #return the value returned by the function if successful * #throws Exception Either an unexpected exception from the function or a {#link RuntimeException} if maxRetries is exceeded */ #SafeVarargs public static <V> V runWithRetriesAndDelay(Callable<V> function, int maxRetries, Duration delay, Class<? extends Exception>... allowedExceptionTypes) throws Exception { final Set<Class<? extends Exception>> exceptions = new HashSet<>(Arrays.asList(allowedExceptionTypes)); for(int i = 1; i <= maxRetries; i++) { try { return function.call(); } catch (Exception e) { if(exceptions.contains(e.getClass())){ // An exception of an expected type System.out.println("Attempt [" + i + "/" + maxRetries + "] Caught exception [" + e.getClass() + "]"); // Pause for the delay time Thread.sleep(delay.toMillis()); }else { // An unexpected exception type throw e; } } } throw new RuntimeException(maxRetries + " retries exceeded"); }
This Solution allows you to configure a reusable functionality for retrying based on certain exception without using any external libraries // Create a Function that suits your need . #FunctionalInterface public interface ThrowableBiFunction<U,T,R> { R apply(U u ,T t) throws Exception; } //Here's the crux of the solution public interface ExceptionRetryable<T, U, R> { int getRetries(); List<Class<? extends Exception>> getRetryableExceptions(); default R execute(ThrowableBiFunction<T, U, R> function, T t, U u) throws Exception { int numberOfRetries = getRetries(); return execute(function, t, u, numberOfRetries); } default R execute(ThrowableBiFunction<T, U, R> function, T t, U u, int retryCount) throws Exception { try { log.info(" Attempting to execute ExceptionRetryable#execute ,Number of remaining retries {} ",retryCount); return function.apply(t, u); } catch (Exception e) { log.info(" error occurred in ExceptionRetryable#execute",e); if (retryCount == 0) throw e; for (Class exp : getRetryableExceptions()) { if (e.getClass() == exp) { return execute(function, t, u, retryCount - 1); } } throw e; } } } // create an implementation for exception retryable public class TestRetryable implements ExceptionRetryable<String, String, List<String>> { #Override public int getRetries() { return 10; } #Override public List<Class<? extends Exception>> getRetryableExceptions() { return Arrays.asList(new Exception1().getClass(), new Exception2().getClass()); ; } } // Finally create a ThrowableBiFunction that encapsulates that piece of code that needs to be retried on exception and an instance of ExceptionRetryable TestRetryable retryable = new TestRetryable(); ThrowableBiFunction<Integer,Long, String> testRetrablefcn = { i, l -> // your code goes here }; Integer i = 0; Long l = 1l; String output = testRetrablefcn.execute(testRetrablefcn,i,l);
Production ready code: #FunctionalInterface public interface Operation { void doCall() throws IOException; default void handleException(Exception e) { //Your custom default implementation } public class OperationHelper { public static void doWithRetry(int maxAttempts, Operation operation) { for (int count = 0; count <= maxAttempts; count++) { try { operation.doCall(); return; } catch (Exception e) { if (count == maxAttempts) { e.printStackTrace(); return; } else { operation.handleException(e); } } } } } Usage with default implementation in code: OperationHelper.doWithRetry(10, () -> //do your job ); Usage when custom exception handle is needed: OperationHelper.doWithRetry(10, new Operation() { #Override public void doIt() { //do some stuff } #Override public void handleException(Exception cause) { //recover from the Exception } });
How to access Hibernate session from src folder?
I would like to know how to access the Service and Domains properly in this sample class placed in src/java folder public class NewsIngestion implements Runnable { private String str; private int num; private Logger log = Logger.getLogger("grails.app"); private static boolean isRunning; private Thread t; private WorkerJobService jobService; private NewsService newsService; public NewsIngestion(String s, int n) { jobService = new WorkerJobService(); newsService = new NewsService(); str = s; num = n; isRunning = false; t = new Thread (this, "NewsIngestion"); } public void run () { while(isRunning){ try{ if(jobService.isJobEnabled("ConsumeFeedsJob") && jobService.lockJob("ConsumeFeedsJob")){ log.info("${this.class.name}: ConsumeFeedsJob started"); try{ // get all sources List sources = (List) InvokerHelper.invokeMethod(RSSFeed.class, "list", null); for(int i = 0; i < sources.size(); i++) { RSSFeed s = (RSSFeed) sources.get(i); // check if it's time to read the source int diff = DateTimeUtil.getSecondsDateDiff(s.getLastChecked(), new Date()); if(s.getLastChecked() == null || diff >= s.getCheckInterval()){ List keyword_list = (List) InvokerHelper.invokeMethod(Keyword.class, "list", null); for(int j = 0; j < keyword_list.size(); j++) { String keyword = (String) keyword_list.get(j); try{ newsService.ingestNewsFromSources(keyword, s); }catch(Exception e){ log.error("${this.class.name}: ${e}"); } log.debug("Completed reading feeds for ${keyword}."); log.info("${this.class.name}: Reading feeds for '${keyword}' (${s.feedName}) took ${Float.toString(st2.getDuration())} second(s)."); } s.setLastChecked(new Date()); InvokerHelper.invokeMethod(RSSFeed.class, "save", null); } log.info("${this.class.name}: Reading feeds for '${s.feedName}' for all keywords took ${Float.toString(st.getDuration())} second(s)."); } }catch(Exception e){ log.error("${this.class.name}: Exception: ${e}"); } log.info("${this.class.name}: ConsumeFeedsJob ended."); // unlock job jobService.unlockJob("ConsumeFeedsJob"); } log.info("alfred: success"); } catch (Exception e){ log.info("alfred exception: " + e.getMessage()); } try { Thread.sleep(5000); } catch (InterruptedException e) { log.info(e.getMessage()); } } } public void start() { if(t == null){ t = new Thread (this, "NewsIngestion"); } if(!isRunning){ isRunning = true; t.start(); } } public void stop() { isRunning = false; } public boolean isRunning() { return isRunning; } } I'm encountering this error message: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here Thanks.
You shouldn't instantiate the service class by yourself, but instead take the class instance from the main context import org.codehaus.groovy.grails.commons.ApplicationHolder def ctx = ApplicationHolder.application.mainContext def newsService = ctx.newsService If you're using Java import org.codehaus.groovy.grails.commons.ApplicationHolder public class SomeClass { SomeService someService; public SomeClass() { someService = (SomeService) ApplicationHolder.getApplication().getMainContext().getBean("someService"); } }
Consider using Spring and #Transactional annotation or AOP.