/* * Copyright (c) 2013 Websquared, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Public License v2.0 * which accompanies this distribution, and is available at * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html * * Contributors: * swsong - initial API and implementation */ package org.fastcatsearch.job; import java.io.PrintWriter; import java.io.Serializable; import java.io.StringWriter; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; import org.fastcatsearch.alert.ClusterAlertService; import org.fastcatsearch.control.JobExecutor; import org.fastcatsearch.env.Environment; import org.fastcatsearch.error.SearchError; import org.fastcatsearch.exception.FastcatSearchException; import org.fastcatsearch.service.ServiceManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public abstract class Job implements Runnable, Serializable { private static final long serialVersionUID = 6296052043270199612L; protected static Logger logger = LoggerFactory.getLogger(Job.class); protected Environment environment; protected JobExecutor jobExecutor; protected long jobId = -1; protected Object args; protected boolean isScheduled; protected boolean noResult; // 결과가 필요없는 단순 호출 작업 private long startTime; private long endTime; public void setEnvironment(Environment environment) { this.environment = environment; } public void setJobExecutor(JobExecutor jobExecutor) { this.jobExecutor = jobExecutor; } public JobExecutor getJobExecutor() { return jobExecutor; } public String toString() { return "[Job] jobId = " + jobId + ", " + getClass().getSimpleName() + ", args = " + args + ", isScheduled=" + isScheduled + ", noResult=" + noResult; } public void setId(long jobId) { this.jobId = jobId; } public long getId() { return jobId; } public void setArgs(Object args) { this.args = args; } public Object getArgs() { return args; } public String getStringArgs(int i) { return ((String[]) args)[i]; } public String getStringArgs() { return (String) args; } public String[] getStringArrayArgs() { return (String[]) args; } public Map<String, Object> getMapArgs() { return (Map<String, Object>) args; } public void setScheduled(boolean isScheduled) { this.isScheduled = isScheduled; } public boolean isScheduled() { return isScheduled; } public void setNoResult() { noResult = true; } public boolean isNoResult() { return noResult; } public long jobStartTime() { return startTime; } public long jobEndTime() { return endTime; } public long duration() { return endTime - startTime; } public abstract JobResult doRun() throws FastcatSearchException; static AtomicInteger count = new AtomicInteger(); public final void run() { startTime = System.currentTimeMillis(); Object result = null; boolean isSuccess = false; try { if (this instanceof MasterNodeJob) { if (!environment.isMasterNode()) { // 실행하면 안된다. throw new RuntimeException("Cannot execute MasterNodeJob on other node : " + environment.myNodeId()); } } JobResult jobResult = doRun(); if(jobResult != null) { result = jobResult.result; isSuccess = jobResult.isSuccess; if (result != null && result instanceof Throwable) { // 다른 서버에서 발생한 에러의 경우는 예외가 result에 담겨있다. // throw (Throwable) result; } } if (jobId == -1) { logger.error("## 결과에 jobId가 없습니다. job={}, result={}", this, jobResult); throw new FastcatSearchException("ERR-00110"); } } catch (SearchError e) { //검색에러는 따로 시스템에러 처리하지 않는다. result = e; isSuccess = false; } catch (Throwable e) { result = e; isSuccess = false; logger.error("error at " + getClass().getName() + " " + args, e); ClusterAlertService clusterAlertService = ServiceManager.getInstance().getService(ClusterAlertService.class); clusterAlertService.alert(e); } finally { //결과셋팅. jobExecutor.result(this, result, isSuccess); endTime = System.currentTimeMillis(); } } protected void logError(Throwable e) { StringWriter sw = new StringWriter(); PrintWriter writer = new PrintWriter(sw); writer.println("#############################################"); e.printStackTrace(writer); writer.println("#############################################"); writer.close(); logger.error(sw.toString()); } public static class JobResult { protected Object result; protected boolean isSuccess; public JobResult() { // result를 넣지않으면 resultFuture.take()시 null객체가 리턴된다. } public JobResult(Object result) { this.isSuccess = !(result instanceof Throwable); this.result = result; } public Object result() { return result; } public boolean isSuccess() { return isSuccess; } @Override public String toString() { return "[JobResult]success=" + isSuccess + ", result=" + result; } } }