All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.alibaba.schedulerx.worker.batch.BaseReqHandler Maven / Gradle / Ivy
package com.alibaba.schedulerx.worker.batch;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import com.alibaba.schedulerx.worker.container.ShutdownMode;
import com.alibaba.schedulerx.worker.log.LogFactory;
import com.alibaba.schedulerx.worker.log.Logger;
import com.alibaba.schedulerx.worker.master.TaskMasterPool;
/**
* used for every parallel/Grid job instance
* every parallel/Grid task master has a BaseReqHandler, a BaseReqHandler will
* batchly retrieve reqs then merge these reqs into a batch request for hugely reducing network reqs number;
* @author yanxun on 2019/1/5.
*/
public abstract class BaseReqHandler {
private long jobInstanceId;
private int coreBatchThreadNum;
private int maxBatchThreadNum;
private int batchSize;
private String batchProcessThreadName;
private String batchRetrieveThreadName;
private ReqQueue reqsQueue;
private Thread batchRetrieveThread;
protected TaskMasterPool taskMasterPool = TaskMasterPool.INSTANCE;
protected ThreadPoolExecutor batchProcessSvc;
protected long defaultSleepMs = 500;
protected long emptySleepMs = 1000;
private volatile T latestRequest;
private static final Logger LOGGER = LogFactory.getLogger(BaseReqHandler.class);
protected Long dispatchDelay;
private volatile AtomicBoolean running = new AtomicBoolean(true);
/**
* onging runnable number, every subclass implement process method should decrement this value when a job was done.
*/
protected AtomicInteger activeRunnableNum = new AtomicInteger(0);
public BaseReqHandler(long jobInstanceId, int coreBatchThreadNum, int maxBatchThreadNum, int batchSize,
ReqQueue queue, String batchProcessThreadName, String batchRetrieveThreadName) {
this.jobInstanceId = jobInstanceId;
this.coreBatchThreadNum = coreBatchThreadNum;
this.maxBatchThreadNum = maxBatchThreadNum > coreBatchThreadNum ? maxBatchThreadNum : coreBatchThreadNum;
this.batchSize = batchSize;
this.batchProcessThreadName = batchProcessThreadName;
this.batchRetrieveThreadName = batchRetrieveThreadName;
reqsQueue = queue;
}
public void start() {
batchProcessSvc = new ThreadPoolExecutor(
coreBatchThreadNum, maxBatchThreadNum, 30, TimeUnit.SECONDS,
new LinkedBlockingQueue(10240), new ThreadFactory() {
private final AtomicInteger nextId = new AtomicInteger(1);
private final String namePrefix = batchProcessThreadName + jobInstanceId + "-";
@Override
public Thread newThread(Runnable r) {
return new Thread(r, namePrefix + nextId.getAndIncrement());
}
}, new ThreadPoolExecutor.CallerRunsPolicy());
batchProcessSvc.allowCoreThreadTimeOut(true);
batchRetrieveThread = new Thread(new Runnable() {
@Override
public void run() {
try {
while (!Thread.currentThread().isInterrupted()) {
List reqs = asyncHandleReqs();
LOGGER.debug("jobInstanceId={}, batch retrieve reqs, size:{}, remain size:{}, batchSize:{}",
jobInstanceId, reqs.size(), reqsQueue.size(), batchSize);
if (reqs.size() < batchSize*0.8f){
if (reqs.isEmpty()) {
// no element in reqs, sleep a while for aggregation
if (running.get()) {
Thread.sleep(emptySleepMs);
} else {
// handler状态已经停止则退出线程
break;
}
} else {
// not reach expect batch size, sleep a while for aggregation
Thread.sleep(defaultSleepMs);
}
}
if (dispatchDelay != null) {
// 支持限速分发
Thread.sleep(dispatchDelay);
}
}
} catch (InterruptedException ie) {
// ignore
} catch (Throwable e) {
LOGGER.error(e);
}
}
}, batchRetrieveThreadName + jobInstanceId);
batchRetrieveThread.start();
}
/**
* logic implemented by subclass for processing this batch of reqs
* @param jobInstanceId id of job instance which these reqs belong to.
* @param reqs batch of reqs
* @param workerIdAddr of PullModel
*/
public abstract void process(long jobInstanceId, List reqs, String workerIdAddr);
public void process(long jobInstanceId, List reqs) {
process(jobInstanceId, reqs, null);
}
public void setWorkThreadNum(int workThreadNum) {
this.coreBatchThreadNum = workThreadNum;
this.maxBatchThreadNum = workThreadNum;
}
public void setBatchSize(int batchSize) {
this.batchSize = batchSize;
}
public void stop() {
try {
stop(true);
} catch (InterruptedException e) {
LOGGER.error("handle stop failed.", e);
}
}
public void stop(boolean immediate) throws InterruptedException {
if (immediate) {
if (batchRetrieveThread != null) {
batchRetrieveThread.interrupt();
}
if (batchProcessSvc != null) {
batchProcessSvc.shutdownNow();
}
if (reqsQueue != null) {
reqsQueue.clear();
}
} else {
this.running.set(false);
// 等待分发线程结束
batchRetrieveThread.join();
if (batchProcessSvc != null) {
batchProcessSvc.shutdown();
batchProcessSvc.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
}
}
}
public void clear(){
if (reqsQueue != null) {
reqsQueue.clear();
}
activeRunnableNum.set(0);
if (batchProcessSvc != null) {
batchProcessSvc.purge();
}
}
public void submitRequest(T request) throws Exception {
if (this.running.get()) {
latestRequest = request;
this.reqsQueue.submitRequest(request);
} else {
throw new IllegalStateException("this handler is not running.");
}
}
public T getLatestRequest() {
return latestRequest;
}
protected int getBatchSize() {
return batchSize;
}
private synchronized List asyncHandleReqs() {
List reqs = reqsQueue.retrieveRequests(getBatchSize());
if (!reqs.isEmpty()) {
activeRunnableNum.incrementAndGet();
process(jobInstanceId, reqs);
}
return reqs;
}
public synchronized List syncHandleReqs(int pageSize, String workerIdAddr) {
List reqs = reqsQueue.retrieveRequests(pageSize);
if (!reqs.isEmpty()) {
activeRunnableNum.incrementAndGet();
process(jobInstanceId, reqs, workerIdAddr);
activeRunnableNum.decrementAndGet();
}
return reqs;
}
/**
* queue has remaining or at least on runnable running, using this method with attention
* because batch process may be async so activeRunnableNum should be decrement when job really down,
* you can look #{TMStatusReqHandler} for example;
* @return
*/
public synchronized boolean isActive() {
return reqsQueue.size() != 0 || activeRunnableNum.get() > 0;
}
}