All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ru.taskurotta.service.recovery.impl.RecoveryThreadsImpl Maven / Gradle / Ivy

package ru.taskurotta.service.recovery.impl;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ru.taskurotta.service.common.ResultSetCursor;
import ru.taskurotta.service.executor.OperationExecutor;
import ru.taskurotta.service.recovery.RecoveryOperation;
import ru.taskurotta.service.recovery.RecoveryThreads;
import ru.taskurotta.service.storage.ProcessService;
import ru.taskurotta.util.Shutdown;

import java.util.Collection;
import java.util.Date;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Lock;

/**
 * Default logic for IncompleteProcessFinder processing. Single scheduled thread with node locking.
 * Injected DAOs should implement environment specific logic.
 * Date: 13.01.14 12:03
 */
public class RecoveryThreadsImpl implements RecoveryThreads {

    private static final Logger logger = LoggerFactory.getLogger(RecoveryThreadsImpl.class);

    public static AtomicInteger processesOnTimeoutFoundedCounter = new AtomicInteger(0);

    private OperationExecutor operationExecutor;
    private ProcessService processService;
    private Lock nodeLock;
    private long findIncompleteProcessPeriod;
    private long incompleteTimeOutMillis;
    private AtomicBoolean enabled = new AtomicBoolean(false);
    private int batchSize;

    public RecoveryThreadsImpl(final ProcessService processService, final Lock nodeLock, final OperationExecutor
            operationExecutor, long findIncompleteProcessPeriod,
                               final long incompleteTimeOutMillis, boolean enabled, int batchSize) {

        this.operationExecutor = operationExecutor;
        this.processService = processService;
        this.nodeLock = nodeLock;
        this.findIncompleteProcessPeriod = findIncompleteProcessPeriod;
        this.incompleteTimeOutMillis = incompleteTimeOutMillis;
        this.batchSize = batchSize;

        if (enabled) {
            start();
        } else {
            logger.warn("Recovery service Incomplete Process Finder is disabled.");
        }

    }

    @Override
    public void start() {

        if (!enabled.compareAndSet(false, true)) {
            // already started
            return;
        }

        // todo: more then one threads may be running after fastest stop() and start() invocation. Current thread
        // may be sleeping and can not catch stop signal from shared atomic long "enabled"
        Thread processFinder = new Thread(new Runnable() {
            @Override
            public void run() {

                while (!Shutdown.isTrue() && enabled.get() && !Thread.currentThread().isInterrupted()) {

                    try {

                        TimeUnit.MILLISECONDS.sleep(findIncompleteProcessPeriod);

                        logger.debug("Fired incomplete process searcher, iteration period[{}] ms", findIncompleteProcessPeriod);

                        //has some processes previously recovered still in processing
                        if (!operationExecutor.isEmpty()) {
                            logger.debug("RecoveryOperationExecutor queue isn't empty. Skip find incomplete processes");
                            continue;
                        }

                        if (nodeLock.tryLock()) {

                            long timeBefore = System.currentTimeMillis() - incompleteTimeOutMillis;

                            if (logger.isDebugEnabled()) {
                                logger.debug("Try to find incomplete processes started before [{}]", new Date(timeBefore));
                            }

                            try (ResultSetCursor incompleteProcessesCursor = processService.findProcesses(timeBefore,
                                    batchSize)) {

                                while (true) {
                                    Collection incompleteProcesses = incompleteProcessesCursor.getNext();

                                    if (incompleteProcesses.isEmpty()) {
                                        logger.debug("Incomplete processes not found");
                                        break;
                                    }

                                    processesOnTimeoutFoundedCounter.addAndGet(incompleteProcesses.size());

                                    for (UUID ip : incompleteProcesses) {
                                        toRecovery(ip);
                                    }

                                    logger.debug("[{}] processes were sent to recovery", incompleteProcesses.size());
                                }

                            }

                        } else {
                            logger.debug("Can't get lock for incomplete processes search, skip iteration");
                        }

                    } catch (Throwable e) {
                        logger.error("IncompleteProcessFinder iteration failed due to error, try to resume in [" + findIncompleteProcessPeriod + "] ms...", e);
                    }
                }
            }
        });

        processFinder.setName("IncompleteProcessFinder");
        processFinder.start();

    }

    public void toRecovery(UUID processId) {
        if (enabled.get()) {
            operationExecutor.enqueue(new RecoveryOperation(processId));
            logger.trace("Process [{}] was sent to recovery queue", processId);
        }
    }

    @Override
    public boolean isStarted() {
        return enabled.get();
    }

    public void stop() {
        enabled.set(false);
    }

    public boolean isEnabled() {
        return enabled.get();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy