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

com.alibaba.dts.client.executor.grid.GridTaskSender Maven / Gradle / Ivy

package com.alibaba.dts.client.executor.grid;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.TimeUnit;

import com.alibaba.dts.client.executor.grid.flowcontrol.FlowControlParameterWatcher;
import com.alibaba.dts.client.executor.grid.queue.TaskEvent;
import com.alibaba.dts.client.executor.grid.queue.send.SendManager;
import com.alibaba.dts.client.executor.grid.unit.FlexibleThreadPoolExecutor;
import com.alibaba.dts.client.executor.job.context.ClientContextImpl;
import com.alibaba.dts.client.executor.job.context.JobContext;
import com.alibaba.dts.common.constants.Constants;
import com.alibaba.dts.common.domain.ExecutableTask;
import com.alibaba.dts.common.domain.remoting.RemoteMachine;
import com.alibaba.dts.common.domain.result.Result;
import com.alibaba.dts.common.domain.result.ResultCode;
import com.alibaba.dts.common.domain.store.TaskSnapshot;
import com.alibaba.dts.common.exception.AccessException;
import com.alibaba.dts.common.exception.InitException;
import com.alibaba.dts.common.logger.SchedulerXLoggerFactory;
import com.alibaba.dts.common.logger.innerlog.Logger;
import com.alibaba.dts.common.util.BytesUtil;
import com.alibaba.dts.common.util.BytesUtil4Client;
import com.alibaba.dts.common.util.NamedThreadFactory;

/**
 * @author Ronan Zhan
 * @date 2016/12/14.
 */
public class GridTaskSender {
    private static final Logger logger = SchedulerXLoggerFactory.getLogger(GridTaskSender.class);

    private SendManager sendManager = new SendManager();

    private long maxBodySize;

    private long flowControlCountGate = 500 * 1000;

    private final ClientContextImpl clientContext;

    private ConcurrentHashMap>> tasksForInsertBufferMap
            = new ConcurrentHashMap>>();
    private ConcurrentHashMap tasksForInsertBufferMapFlag = new ConcurrentHashMap();

    private ExecutorService reSendExecutorService = new FlexibleThreadPoolExecutor(8, 16, 60, TimeUnit.SECONDS, new LinkedBlockingDeque(), new NamedThreadFactory("SchedulerX-Tasks-ReSend-Thread-"));

    public GridTaskSender(ClientContextImpl clientContext) {
        this.clientContext = clientContext;
    }

    private void initSchedulerXSendQueue() throws InitException {
        if (clientContext == null) {
            logger.equals("[GridTaskSender] clientContext is null!");
            throw new InitException("[GridTaskSender] clientContext is null!");
        }

        sendManager.init(clientContext);
        //sendManager.setTaskMergeHandler(taskMergeHandler);
        //sendManager.initialProcessChain(this.clientContext);
        //sendManager.startWork();
    }

    public void init() throws InitException {

        try {
            maxBodySize = clientContext.getClientConfig().getMaxBodySize();
            initSchedulerXSendQueue();
            initTasksForInsertBufferConsumer();
            logger.info("[GridTaskSender]: init over");
        } catch (Throwable e) {
            logger.error("[GridTaskSender]: init error:", e);
        }

    }

    private void initTasksForInsertBufferConsumer() throws InitException {
        new TaskForInsertConsumer().init();
    }

    public Result dispatchTaskList(List taskList, String taskName, JobContext jobContext,
                                            int dispatchMode) {
        long jobId = jobContext.getJob().getId();
        long jobInstanceId = jobContext.getJobInstanceSnapshot().getId();

        logger.info("{} tasks dispatched, jobId={}, jobInstanceId={}", taskList.size(), jobId, jobInstanceId);
        if (clientContext.getGridJobManager().containsInterruptedJobInstance(
                jobContext.getJobInstanceSnapshot().getId())) {
            logger.warn("[GridTaskSender]: dispatchTaskList is interrupted forcedly:"
                    + ",jobId=" + jobId
                    + ",jobInstanceId=" + jobInstanceId
                    + ",total tasks=" + taskList.size());
            return new Result(false);
        }

        boolean result = true;

        List taskEvents = new ArrayList();

        try {

            List nodes = null;
            int retryCount = 10;
            while (retryCount > 0) {
                nodes = clientContext.getNodeRemoting().getNodes(clientContext.getClientConfig().getGroupId(), jobId, jobContext.getJob().getType());
                if (nodes == null || nodes.isEmpty()) {
                    logger.warn("there is no working nodes existed, groupId={}, jobId={}, so it will retry {} times", clientContext.getClientConfig().getGroupId(), jobId, retryCount);
                    if (--retryCount <= 0) {
                        throw new RuntimeException("there is no working nodes existed, groupId={}, jobId={}, and it has retried for 10 times");
                    }
                    TimeUnit.SECONDS.sleep(10);
                    continue;
                } else {
                    break;
                }
            }

            sendManager.resetRoutesMachines(jobContext.getJob().getId(), nodes);

            int position = 0;

            long successProcess = 0;
            long totalStart = System.currentTimeMillis();

            int batchSize = 3000;
            //if (dispatchMode == 1) { batchSize = calculateBatchSize(taskList, nodes); }

            while (position < taskList.size()) {

                if (isInterruptedInstance(jobContext.getJobInstanceSnapshot().getId())) {

                    logger.warn("[GridTaskSender]: dispatchTaskList is interrupted forcedly:"
                            + ",jobId:" + jobContext.getJob().getId()
                            + ",jobInstanceId:" + jobContext.getJobInstanceSnapshot().getId()
                            + ",total tasks:" + taskList.size()
                            + ",put schedulerXSendQueue tasks:" + successProcess);
                    Result resultIntercept = new Result(false);
                    resultIntercept.setResultCode(ResultCode.TASK_SEND_INTERRUPT);
                    return resultIntercept;
                }

                ExecutableTask executableTask = null;

                long start = System.currentTimeMillis();

                if (dispatchMode == 1) {

                    executableTask = new ExecutableTask(jobContext.getJob(), jobContext.getJobInstanceSnapshot());
                    fillTaskSnapshot(executableTask, taskList.get(position), taskName);

                    TaskEvent taskEvent = new TaskEvent();
                    taskEvent.setExecutableTask(executableTask);
                    taskEvent.setTask(taskList.get(position));

                    if ((position + 1) % batchSize == 0) {
                        taskEvents.add(taskEvent);

                        //FlowControlStrategy flowControlStrategy = clientContext.getNodeConfig()
                        //    .getFlowControlStrategy();
                        //if (flowControlStrategy == FlowControlStrategy.H2_COUNT_MULTI
                        //    && FlowControlParameterWatcher.dbTasksCount.get() > flowControlCountGate) {//流控
                        //    List taskEventTemp = new ArrayList(taskEvents);
                        //    BlockingQueue> tasksForInsertBuffer = tasksForInsertBufferMap.get(
                        //        jobContext.getJobInstanceSnapshot().getId());
                        //    if (tasksForInsertBuffer == null) {
                        //        tasksForInsertBuffer = new ArrayBlockingQueue>(512 * 1024);
                        //        BlockingQueue> tasksForInsertBufferExsit = tasksForInsertBufferMap
                        //            .putIfAbsent(jobContext.getJobInstanceSnapshot().getId(), tasksForInsertBuffer);
                        //        if (tasksForInsertBufferExsit != null) {
                        //            tasksForInsertBuffer = tasksForInsertBufferExsit;
                        //        }
                        //    }
                        //    tasksForInsertBuffer.put(taskEventTemp);
                        //} else {
                        clientContext.getFlowControlChain().control(jobContext);
                        persistTasks(taskEvents, jobInstanceId);
                        sendManager.putTasksToRouteQueue(taskEvents, jobInstanceId);

                        long end = System.currentTimeMillis();
                        logger.debug(
                                "[GridTaskSender]: dispatchTaskList,executableTask has been put to schedulerXSendQueue, "
                                        + "jobId={}, jobInstanceId={}, taskName={}, consumptionTime={}, size={}",
                                executableTask.getJob().getId(), executableTask.getJobInstanceSnapshot().getId(), taskName,
                                (end - start), taskEvents.size());
                        //}
                        taskEvents.clear();
                    } else {
                        taskEvents.add(taskEvent);
                    }
                    successProcess++;
                } else if (dispatchMode == 2) {
                    TaskSnapshot taskSnapshot = (TaskSnapshot) taskList.get(position);

                    executableTask = new ExecutableTask(jobContext.getJob(), jobContext.getJobInstanceSnapshot());
                    executableTask.setTaskSnapshot(taskSnapshot);
                    executableTask.getTaskSnapshot().setReSent(true);
                    executableTask.setCompensation(true);

                    TaskEvent taskEvent = new TaskEvent();
                    taskEvent.setExecutableTask(executableTask);
                    taskEvent.setTask(getTaskObject(taskSnapshot));

                    sendManager.putSingleTaskToRouteQueue(taskEvent);
                    successProcess++;
                } else if (dispatchMode == 3) {
                    TaskSnapshot taskSnapshot = (TaskSnapshot) taskList.get(position);

                    executableTask = new ExecutableTask(jobContext.getJob(), jobContext.getJobInstanceSnapshot());
                    executableTask.setTaskSnapshot(taskSnapshot);

                    TaskEvent taskEvent = new TaskEvent();
                    taskEvent.setExecutableTask(executableTask);
                    taskEvent.setTask(getTaskObject(taskSnapshot));
                    sendManager.putSingleTaskToRouteQueue(taskEvent);
                    successProcess++;
                }

                position = position + 1;

            }

            if (dispatchMode == 1) {
                if (taskEvents.size() > 0) {
                    clientContext.getFlowControlChain().control(jobContext);
                    persistTasks(taskEvents, jobInstanceId);
                    sendManager.putTasksToRouteQueue(taskEvents, jobInstanceId);
                    taskEvents.clear();
                }
            }

            long totalEnd = System.currentTimeMillis();

            logger.debug(
                    "[GridTaskSender]: dispatchTaskList,executableTask has been put to schedulerXSendQueue, jobId={}, "
                            + "jobInstanceId={}, total={}, put schedulerXSendQueue tasks={}, taskName={}, consumptionTime={}",
                    jobContext.getJob().getId(), jobContext.getJobInstanceSnapshot().getId(), taskList.size(),
                    successProcess, taskName, (totalEnd - totalStart));

        } catch (Throwable e) {
            result = false;
            logger.error("[GridTaskSender]: dispatchTaskList error,", e);
        }

        return new Result(result);
    }

    // calculate batch size by nodes size, 2 multiplied is for reason the result we can make dispatch more dispersive
    private int calculateBatchSize(List taskList, List nodes) {
        int batchSize = clientContext.getNodeConfig().getTaskInsertBatchSize();
        if (batchSize == 0) {

            if (taskList.size() < nodes.size() * 2) {
                batchSize = 1;
            } else {
                batchSize = taskList.size() / (nodes.size() * 2);
            }
            if (batchSize > 3000) {
                batchSize = 3000;
            }
            return batchSize;
        }
        return batchSize;
    }

    public Result dispatchTaskList(List taskList, String taskName, JobContext jobContext) {
        return dispatchTaskList(taskList, taskName, jobContext, 1);
    }

    public Result dispatchCompensateTaskList(List taskList, JobContext jobContext) {
        return dispatchTaskList(taskList, null, jobContext, 2);
    }

    public Result dispatchRetryTaskList(List taskList, JobContext jobContext) {
        return dispatchTaskList(taskList, null, jobContext, 3);
    }

    class TaskForInsertConsumer {

        private ExecutorService bossThreadPool = Executors.newSingleThreadExecutor(
                new NamedThreadFactory("SchedulerX-TaskForInsertConsumer-Boss-"));
        private ExecutorService workerThreadPool = Executors.newFixedThreadPool(16,
                new NamedThreadFactory("SchedulerX-TaskForInsertConsumer-Worker-"));

        public void init() throws InitException {
            try {
                bossThreadPool.submit(new Runnable() {
                    @Override
                    public void run() {
                        while (true) {
                            try {
                                for (Map.Entry>> entry : tasksForInsertBufferMap
                                        .entrySet()) {
                                    final Long jobInstanceId = entry.getKey();
                                    final BlockingQueue> queue = entry.getValue();

                                    if (tasksForInsertBufferMapFlag.containsKey(jobInstanceId)) {
                                        continue;
                                    }
                                    tasksForInsertBufferMapFlag.put(jobInstanceId, true);
                                    workerThreadPool.submit(new Runnable() {
                                        @Override
                                        public void run() {
                                            while (tasksForInsertBufferMap.containsKey(jobInstanceId)) {
                                                try {
                                                    final List taskEvents = queue.poll(10, TimeUnit.SECONDS);
                                                    if (taskEvents == null || taskEvents.size() <= 0) {
                                                        continue;
                                                    }
                                                    while (true) {
                                                        if (FlowControlParameterWatcher.dbTasksCount.get()
                                                                < flowControlCountGate) {

                                                            TaskEvent taskEvent = taskEvents.get(0);
                                                            persistTasks(taskEvents, jobInstanceId);
                                                            sendManager.putTasksToRouteQueue(taskEvents, jobInstanceId);
                                                            logger.debug(
                                                                    "[TaskForInsertConsumer]: dispatchTaskList, "
                                                                            + "executableTask has been put to "
                                                                            + "schedulerXSendQueue, jobId={}, "
                                                                            + "jobInstanceId={}, size={}",
                                                                    taskEvent.getExecutableTask().getJob().getId(),
                                                                    taskEvent.getExecutableTask().getJobInstanceSnapshot()
                                                                            .getId(), taskEvents.size());
                                                            break;
                                                        } else {
                                                            TimeUnit.SECONDS.sleep(5);
                                                        }
                                                    }
                                                } catch (Throwable throwable) {
                                                    logger.error("TaskForInsertConsumer error", throwable);
                                                }
                                            }
                                        }
                                    });
                                }
                                TimeUnit.SECONDS.sleep(1);
                            } catch (Throwable throwable) {
                                logger.error("TaskForInsertConsumer error", throwable);
                            }
                        }
                    }
                });
            } catch (
                    Throwable throwable)

            {
                throw new InitException(throwable);
            }

        }

    }

    private void fillTaskSnapshot(ExecutableTask executableTask, Object task, String taskName) {
        byte[] body = null;
        try {
            body = BytesUtil4Client.objectToBytes(task);
        } catch (Throwable e) {
            logger.error("[GridTaskSender]: fillTaskSnapshot objectToBytes error"
                    + ", taskName:" + taskName
                    + ", task:" + task, e);
        }
        if (BytesUtil4Client.isEmpty(body)) {
            logger.error("[GridTaskSender]: fillTaskSnapshot objectToBytes body is empty"
                    + ", taskName:" + taskName
                    + ", task:" + task);
            return;
        }

        if (body.length > maxBodySize) {
            throw new RuntimeException("[GridTaskSender]: single task is too large, more than 64KB");
        }

        TaskSnapshot taskSnapshot = new TaskSnapshot();
        taskSnapshot.setGmtCreate(new Date());
        taskSnapshot.setGmtModified(new Date());
        taskSnapshot.setJobInstanceId(executableTask.getJobInstanceSnapshot().getId());
        taskSnapshot.setJobProcessor(executableTask.getJob().getJobProcessor());
        taskSnapshot.setBody(body);
        taskSnapshot.setStatus(Constants.TASK_STATUS_INIT);
        taskSnapshot.setTaskName(taskName);
        taskSnapshot.setRetryCount(0);

        executableTask.setTaskSnapshot(taskSnapshot);

    }

    protected Object getTaskObject(TaskSnapshot taskSnapshot) {

        Object resultTask = null;
        if (Constants.DEFAULT_ROOT_LEVEL_TASK_NAME.equals(taskSnapshot.getTaskName())) {
            if (BytesUtil.isEmpty(taskSnapshot.getBody())) {
                logger.error("[GridTaskSender]: BytesUtil setTask bytesToObject error, body is empty"
                        + ", instanceId:" + taskSnapshot.getJobInstanceId()
                        + ", id:" + taskSnapshot.getId());
                return null;
            }
            try {
                resultTask = BytesUtil.bytesToObject(taskSnapshot.getBody());
            } catch (Throwable e) {
                logger.error("[GridTaskSender]: BytesUtil setTask bytesToObject error"
                        + ", instanceId:" + taskSnapshot.getJobInstanceId()
                        + ", id:" + taskSnapshot.getId(), e);
            }
        } else {
            if (BytesUtil4Client.isEmpty(taskSnapshot.getBody())) {
                logger.error("[GridTaskSender]: BytesUtil4Client setTask bytesToObject error, body is empty"
                        + ", instanceId:" + taskSnapshot.getJobInstanceId()
                        + ", id:" + taskSnapshot.getId());
                return null;
            }
            try {
                resultTask = BytesUtil4Client.bytesToObject(taskSnapshot.getBody());
            } catch (Throwable e) {
                logger.error("[GridTaskSender]: BytesUtil4Client setTask bytesToObject error"
                        + ", instanceId:" + taskSnapshot.getJobInstanceId()
                        + ", id:" + taskSnapshot.getId(), e);
            }
        }

        return resultTask;
    }

    private void persistTasks(List taskEvents, long jobInstanceId) {
        if (taskEvents.isEmpty()) {
            return;
        }
        List taskSnapshots = new ArrayList();
        if (clientContext.getGridJobManager().containsInterruptedJobInstance(jobInstanceId)) {
            return;
        }
        for (TaskEvent taskEvent : taskEvents) {
            TaskSnapshot taskSnapshot = taskEvent.getExecutableTask().getTaskSnapshot();
            taskSnapshot.setId(clientContext.getIdWorker().nextId());
            taskSnapshots.add(taskSnapshot);
        }

        try {
            clientContext.getStore().getTaskSnapshotDao().insertBatch(taskSnapshots);
        } catch (AccessException e) {
            logger.error("failed to insert tasksnapshots batch. jobInstanceId=" + jobInstanceId, e);
        }

    }

    public void addInterruptedJobInstance(long instanceId) {
        try {
            clientContext.getGridJobManager().addInterruptedJobInstance(instanceId);
            logger.info("[GridTaskSender]: addInterceptInstance instanceId:" + instanceId);
        } catch (Throwable e) {
            logger.error("[GridTaskSender]: addInterceptInstance error,instanceId:" + instanceId, e);
        }
    }

    public void removeInterruptedJobInstance(long instanceId) {
        try {
            clientContext.getGridJobManager().removeInterruptedJobInstance(instanceId);
            logger.info("[GridTaskSender]: removeInterceptInstance instanceId:" + instanceId);
        } catch (Throwable e) {
            logger.error("[GridTaskSender]: removeInterceptInstance error,instanceId:" + instanceId, e);
        }
    }

    public boolean isInterruptedInstance(long instanceId) {
        if (clientContext.getGridJobManager().containsInterruptedJobInstance(instanceId)) {
            return true;
        }
        return false;
    }

    public ExecutorService getReSendExecutorService() {
        return reSendExecutorService;
    }

    public ConcurrentHashMap>> getTasksForInsertBufferMap() {
        return tasksForInsertBufferMap;
    }

    public void clearInsertBuffer(long jobInstanceId) {
        tasksForInsertBufferMap.remove(jobInstanceId);
        tasksForInsertBufferMapFlag.remove(jobInstanceId);
    }

    public SendManager getSendManager() {
        return sendManager;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy