public CurrentStatsAsyncTasks(CurrentStats currentStats, Storage storage) { this.currentStats = currentStats; this.statsPersistence = new StatsPersistence(storage); collectingExecutor = new ThreadPoolExecutor(0, 1, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(), runnable -> { Thread t = Executors.defaultThreadFactory().newThread(runnable); t.setDaemon(true);//we don't want to block JVM shutdown t.setName(COLLECTOR_THREAD_NAME); return t; }); savingExecutor = new ThreadPoolExecutor(0, 1, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(), runnable -> { Thread t = Executors.defaultThreadFactory().newThread(runnable); t.setDaemon(true);//we don't want to block JVM shutdown t.setName(SAVING_THREAD_NAME); return t; }); }
private boolean safeSave() { //this stuff runs in new thread log.debug("persisting stats"); //don't lock for long here! - just get stats we plan to save and start to collect new values Stats oldStats = currentStats.lockReadStats(stats -> currentStats.resetStats() ); boolean saved = statsPersistence.safeSave(oldStats); if( !saved ){ log.debug("failed to save stats - returning stats in order to try again later"); currentStats.lockReadStats(stats -> { stats.merge(oldStats, true); return true; }); } else { log.debug("saved stats - running stats cleanup"); statsPersistence.safeCleanup(); } log.debug("finished persisting stats"); return true; }
/** * @param stats * @return true if successfully saved stats - otherwise false */ public boolean safeSave(Stats stats){ if( storage == null ){ return false; } try{ ensureDatesAreSet(stats); long start = System.currentTimeMillis(); storage.save(stats, appInstance, appType); lastSave.set(dateUtil.now().getTime()); lastError.set(0); log.info("Saved stats in {}ms", System.currentTimeMillis() - start); return true; }catch(Exception e){ Throwable cause = firstNonNull(getRootCause(e), e); log.warn("Failed to save stats - next attempt in 5 minutes. Error type: {}, Message: {}", cause.getClass().getName(), cause.getMessage()); log.debug("Failed to save stats - next attempt in 5 minutes. ", e); lastError.set(dateUtil.now().getTime()); return false; } }
public void triggerAsyncTask() { try{ if (!enabled || (collectingTaskResult != null && !collectingTaskResult.isDone())) { //previous task is still running //it's not a perfect synchronization but it doesn't have to be return; } log.debug("Creating new async task for collector: {}", COLLECTOR_ID); collectingTaskResult = collectingExecutor.submit(() -> { //this stuff runs in new thread safeSleep(); log.debug("started async task for collector: {}", COLLECTOR_ID); try { currentStats.processAllFromQueue(); if (statsPersistence != null && statsPersistence.threadSafeShouldSave()) { //run save in another thread so we don't block processing elements from queue triggerAsyncSafeSave(); } } catch (Exception e) { currentStats.setFatalError(getStacktrace(e)); log.debug("error occurred when processing async task for collector: {}", COLLECTOR_ID, e); } log.debug("finished async task for collector: {}", COLLECTOR_ID); }); log.debug("Created new async task for collector: {}", COLLECTOR_ID); }catch(Exception e){ log.warn("Failed to trigger async task for collector: {}", COLLECTOR_ID, e); } }