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

com.lifeonwalden.springscheduling.task.Task Maven / Gradle / Ivy

There is a newer version: 0.2.11
Show newest version
/**
 * Copyright 2016 HongLu
 * 

* 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.lifeonwalden.springscheduling.task; import com.lifeonwalden.springscheduling.BaseTrigger; import com.lifeonwalden.springscheduling.monitor.Monitor; import com.lifeonwalden.springscheduling.monitor.TaskEvent; import com.lifeonwalden.springscheduling.monitor.TaskEventType; import org.apache.commons.lang3.time.StopWatch; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import java.time.LocalDateTime; import java.time.ZoneId; import java.time.temporal.ChronoUnit; import java.util.*; import java.util.concurrent.*; public abstract class Task implements Runnable, ScheduledFuture { private final static Logger logger = LogManager.getLogger(Task.class); private final Object triggerContextMonitor = new Object(); protected String id; protected String name; protected Map param; protected TaskTriggerContext triggerContext; protected Monitor monitor; protected boolean canRetry = false; protected int retryTimes = 0; protected int maxRetryTimes = 3; protected boolean stopped = false; /** * always retry from the beginning of worker list */ protected boolean alwaysFromBeginning = false; /** * retry after 30 Minutes */ protected long retryAfter = 1800; protected ScheduledExecutorService executor; protected TaskStatusEnum status = TaskStatusEnum.WAITING; private ScheduledFuture currentFuture; public Task(String id, String name, TaskTriggerContext triggerContext) { this.id = id; this.name = name; this.triggerContext = triggerContext; } public Task(String id, String name, TaskTriggerContext triggerContext, Monitor monitor) { this.id = id; this.name = name; this.monitor = monitor; this.triggerContext = triggerContext; } public Map getParam() { return param; } public Task setParam(Map param) { this.param = param; return this; } public int getMaxRetryTimes() { return maxRetryTimes; } public void setMaxRetryTimes(int maxRetryTimes) { this.maxRetryTimes = maxRetryTimes; } public int getRetryTimes() { return retryTimes; } public void setRetryTimes(int retryTimes) { this.retryTimes = retryTimes; } public boolean isCanRetry() { return canRetry; } public void setCanRetry(boolean canRetry) { this.canRetry = canRetry; } public boolean isAlwaysFromBeginning() { return alwaysFromBeginning; } public void setAlwaysFromBeginning(boolean alwaysFromBeginning) { this.alwaysFromBeginning = alwaysFromBeginning; } public long getRetryAfter() { return retryAfter; } /** * retry after {retryAfter} seconds * * @param retryAfter */ public void setRetryAfter(long retryAfter) { this.retryAfter = retryAfter; } public ScheduledExecutorService getExecutor() { return executor; } public void setExecutor(ScheduledExecutorService executor) { this.executor = executor; } public TaskStatusEnum getStatus() { return status; } public Task setStatus(TaskStatusEnum status) { this.status = status; return this; } public String getId() { return id; } public String getName() { return name; } public TaskTriggerContext getTriggerContext() { return triggerContext; } public void setTriggerContext(TaskTriggerContext triggerContext) { this.triggerContext = triggerContext; } public BaseTrigger getTrigger() { return triggerContext.getTrigger(); } public ScheduledFuture schedule() { if (isStopped()) { return null; } synchronized (this.triggerContextMonitor) { Date scheduledExecutionTime = this.triggerContext.getTrigger().nextExecutionTime(this.triggerContext); if (scheduledExecutionTime == null) { return null; } long initialDelay = scheduledExecutionTime.getTime() - System.currentTimeMillis(); logger.info("Schedule task [{}] run @ {}", this.name, scheduledExecutionTime.toString()); this.currentFuture = this.executor.schedule(this, initialDelay, TimeUnit.MILLISECONDS); return this; } } private void _run(Map param) { Date nextExecutionTime = null, actualExecutionTime = null, completionTime = null; List failPrintList = null; TaskEvent startTaskEvent = new TaskEvent(); final String taskId = this.id; try { Map _param = null != param ? param : (null == this.param ? new WeakHashMap() : new WeakHashMap( this.param)); actualExecutionTime = new Date(); if (null != monitor) { final Date _actualExecutionTime = actualExecutionTime; new Thread(new Runnable() { @Override public void run() { monitor.notificate(startTaskEvent.setHappendTime(_actualExecutionTime).setTaskId(taskId).setType(TaskEventType.START) .setParam(_param)); } }).start(); } this.status = TaskStatusEnum.RUNNING; logger.info("Task [{}] Start", this.name); StopWatch stopWatch = new StopWatch(); stopWatch.start(); failPrintList = doJob(_param); stopWatch.stop(); logger.info("Task [{}] End, the task cost time : {}", this.name, stopWatch.getTime()); this.status = TaskStatusEnum.COMPLETED; } catch (Throwable e) { logger.error("Task failed", e); this.status = TaskStatusEnum.FAILED; failPrintList = Arrays.asList(e.getMessage()); } completionTime = new Date(); nextExecutionTime = getTrigger().nextExecutionTime(triggerContext); if (null != failPrintList && this.canRetry && (0 == this.maxRetryTimes || this.maxRetryTimes > this.retryTimes)) { nextExecutionTime = Date.from(LocalDateTime.now().plus(this.retryAfter, ChronoUnit.SECONDS).atZone(ZoneId.systemDefault()).toInstant()); this.retryTimes++; logger.info("Task {} going to retry the {} time.", this.name, this.retryTimes); } else { this.retryTimes = 0; } if (null != monitor) { final TaskStatusEnum taskStatus = this.status; final List _failPrintList = failPrintList; final Date _nextExecutionTime = nextExecutionTime; new Thread(new Runnable() { @Override public void run() { monitor.notificate(new TaskEvent().setHappendTime(new Date()).setTaskId(taskId) .setType(TaskStatusEnum.COMPLETED == taskStatus ? TaskEventType.COMPELETE : TaskEventType.FAIL) .setFailPrintList(_failPrintList).setNextExecutionTime(_nextExecutionTime) .setStartTime(startTaskEvent.getHappendTime()).setParam(startTaskEvent.getParam())); } }).start(); } synchronized (this.triggerContextMonitor) { this.triggerContext.update(nextExecutionTime, actualExecutionTime, completionTime); if (!this.currentFuture.isCancelled()) { schedule(); } } } public abstract List doJob(Map param); @Override public void run() { _run(null); } @Override public long getDelay(TimeUnit unit) { ScheduledFuture curr; synchronized (this.triggerContextMonitor) { curr = this.currentFuture; } return curr.getDelay(unit); } @Override public int compareTo(Delayed other) { if (this == other) { return 0; } long diff = getDelay(TimeUnit.MILLISECONDS) - other.getDelay(TimeUnit.MILLISECONDS); return (diff == 0 ? 0 : ((diff < 0) ? -1 : 1)); } @Override public boolean cancel(boolean mayInterruptIfRunning) { synchronized (this.triggerContextMonitor) { return this.currentFuture.cancel(mayInterruptIfRunning); } } @Override public boolean isCancelled() { synchronized (this.triggerContextMonitor) { return this.currentFuture.isCancelled(); } } @Override public boolean isDone() { synchronized (this.triggerContextMonitor) { return this.currentFuture.isDone(); } } @Override public Object get() throws InterruptedException, ExecutionException { ScheduledFuture curr; synchronized (this.triggerContextMonitor) { curr = this.currentFuture; } return curr.get(); } @Override public Object get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { ScheduledFuture curr; synchronized (this.triggerContextMonitor) { curr = this.currentFuture; } return curr.get(timeout, unit); } public boolean isStopped() { return stopped; } public void setStopped(boolean stopped) { this.stopped = stopped; } }