com.blacklocus.qs.worker.WorkerQueueItemHandler.java Source code

Java tutorial

Introduction

Here is the source code for com.blacklocus.qs.worker.WorkerQueueItemHandler.java

Source

/**
 * Copyright 2013 BlackLocus
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.blacklocus.qs.worker;

import com.blacklocus.qs.QueueItemHandler;
import com.blacklocus.qs.worker.api.QSLogService;
import com.blacklocus.qs.worker.api.QSTaskService;
import com.blacklocus.qs.worker.api.QSWorker;
import com.blacklocus.qs.worker.api.QSWorkerIdService;
import com.blacklocus.qs.worker.model.QSLogModel;
import com.blacklocus.qs.worker.model.QSTaskModel;
import com.github.rholder.moar.concurrent.QueueingStrategy;
import com.google.common.collect.ImmutableMap;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

/**
 * @author Jason Dunkelberger (dirkraft)
 */
class WorkerQueueItemHandler implements QueueItemHandler<QSTaskModel, TaskKit, Object> {

    private static final Logger LOG = LoggerFactory.getLogger(WorkerQueueItemHandler.class);

    private final QueueingStrategy<QSTaskModel> queueingStrategy;
    private final QSTaskService taskService;
    private final QSLogService logService;
    private final QSWorkerIdService workerIdService;
    private final Map<String, QSWorker> workers;

    WorkerQueueItemHandler(QueueingStrategy<QSTaskModel> queueingStrategy, QSTaskService taskService,
            QSLogService logService, QSWorkerIdService workerIdService, Map<String, QSWorker> workers) {
        this.queueingStrategy = queueingStrategy;
        this.taskService = taskService;
        this.logService = logService;
        this.workerIdService = workerIdService;
        this.workers = workers;
    }

    @SuppressWarnings("unchecked")
    @Override
    public void withFuture(QSTaskModel task, final Future<Pair<QSTaskModel, Object>> future) {
        // I don't know if this is useful or not.

        QSWorker worker = workers.get(task.handler);
        if (worker == null) {
            throw new RuntimeException("No worker available for worker identifier: " + task.handler);
        }

        final TaskKitFactory factory = new TaskKitFactory(task, worker, logService, workerIdService);
        worker.withFuture(factory, new Future<Pair<TaskKitFactory, Object>>() {
            @Override
            public boolean cancel(boolean mayInterruptIfRunning) {
                return future.cancel(mayInterruptIfRunning);
            }

            @Override
            public boolean isCancelled() {
                return future.isCancelled();
            }

            @Override
            public boolean isDone() {
                return future.isDone();
            }

            @Override
            public Pair<TaskKitFactory, Object> get() throws InterruptedException, ExecutionException {
                Pair<QSTaskModel, Object> theFuture = future.get();
                return Pair.of(factory, theFuture.getRight());
            }

            @Override
            public Pair<TaskKitFactory, Object> get(long timeout,
                    @SuppressWarnings("NullableProblems") TimeUnit unit)
                    throws InterruptedException, ExecutionException, TimeoutException {
                Pair<QSTaskModel, Object> theFuture = future.get(timeout, unit);
                return Pair.of(factory, theFuture.getRight());
            }
        });
    }

    @SuppressWarnings("unchecked")
    @Override
    public TaskKit convert(QSTaskModel task) throws Exception {
        task.started = System.currentTimeMillis();
        task.workerId = workerIdService.getWorkerId();
        LOG.info("Task started: {}", task);
        logService.startedTask(task);

        QSWorker handler = workers.get(task.handler);
        if (handler == null) {
            throw new RuntimeException("No worker available for handler identifier: " + task.handler);
        }

        // The worker only needs to specify how it wants to deserialize its params.
        return handler.convert(new TaskKitFactory(task, handler, logService, workerIdService));
    }

    @SuppressWarnings("unchecked")
    @Override
    public Object process(TaskKit kit) throws Exception {
        return kit.worker.process(kit);
    }

    @SuppressWarnings("unchecked")
    @Override
    public void onSuccess(QSTaskModel task, TaskKit kit, Object result) {
        kit.worker.onSuccess(kit.factory, kit, result);

        queueingStrategy.onBeforeRemove();

        taskService.closeTask(task);
        LOG.info("Task succeeded: {}", task);

        task.finishedHappy = true;
    }

    @SuppressWarnings("unchecked")
    @Override
    public void onError(QSTaskModel task, TaskKit kit, Throwable throwable) {
        try {
            kit.worker.onError(kit.factory, kit, throwable);
        } catch (Throwable anotherThrowable) {
            LOG.warn("There was an error in worker.onError It will replace the current throwable.",
                    anotherThrowable);
            throwable = anotherThrowable;
        }

        queueingStrategy.onBeforeRemove();

        ImmutableMap<String, ImmutableMap<String, String>> exceptionDetails = ImmutableMap.of("exception",
                ImmutableMap.of("class", throwable.getClass().getName(), "message", throwable.getMessage(),
                        "stackTrace", ExceptionUtils.getStackTrace(throwable)));
        QSLogModel logTick = new QSLogModel(task.taskId, workerIdService.getWorkerId(), task.handler,
                System.currentTimeMillis(), exceptionDetails);
        if (LOG.isDebugEnabled()) {
            LOG.debug("Task erred: {}", logTick, throwable);
        } else {
            LOG.info("Task erred: {}", logTick);
        }
        logService.log(logTick);

        if (--task.remainingAttempts > 0) {
            taskService.resetTask(task);
        } else {
            taskService.closeTask(task);
        }

        task.finishedHappy = false;
    }

    @SuppressWarnings("unchecked")
    @Override
    public void onComplete(QSTaskModel task, TaskKit kit, Object result) {
        kit.worker.onComplete(kit.factory, kit, result);

        task.finished = System.currentTimeMillis();
        task.elapsed = task.finished - task.started;
        logService.completedTask(task);

        queueingStrategy.onAfterRemove(task);
    }

}