package me.hao0.antares.store.manager; import me.hao0.antares.common.dto.ShardFinishDto; import me.hao0.antares.common.log.Logs; import me.hao0.antares.common.model.JobInstanceShard; import me.hao0.antares.common.model.enums.JobInstanceShardStatus; import me.hao0.antares.common.model.enums.ShardOperateRespCode; import me.hao0.antares.store.dao.JobInstanceShardDao; import me.hao0.antares.store.exception.ShardOperateException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; import java.util.Date; /** * The job instance's shards manager * Author: haolin * Email: haolin.h0@gmail.com */ @Repository public class JobInstanceShardManager { @Autowired private JobInstanceShardDao jobInstanceShardDao; /** * Save the job instance * @param progress the job instance progress * @return return true if save successfully, or false */ public Boolean save(JobInstanceShard progress){ if (jobInstanceShardDao.save(progress)){ if (jobInstanceShardDao.bindInstance(progress.getInstanceId(), progress.getId())){ return Boolean.TRUE; } else { // try to delete the dirty data jobInstanceShardDao.delete(progress.getId()); } } return Boolean.FALSE; } /** * Delete the job instance progress * @param shardId the job instance shard id * @return return true if delete successfully, or false */ public Boolean delete(Long shardId){ JobInstanceShard progress = jobInstanceShardDao.findById(shardId); if (progress == null){ return Boolean.TRUE; } if (jobInstanceShardDao.unbindInstance(progress.getInstanceId(), shardId)){ return jobInstanceShardDao.delete(shardId); } return Boolean.FALSE; } /** * Get and update the shard for pulling shard * @param jobInstanceId the job instance id * @param maxShardPullCount the max shard pull count * @param client the client host * @return the shard */ public JobInstanceShard pullShard(Long jobInstanceId, String client, Integer maxShardPullCount) { Long shardId = jobInstanceShardDao.pullShardFromNewShardsSet(jobInstanceId); if (shardId == null){ // all shards are pulled throw new ShardOperateException(ShardOperateRespCode.SHARD_NO_AVAILABLE); } JobInstanceShard shard = checkShardStatus(shardId); // check the max pull count if (shard.getPullCount() > maxShardPullCount){ // we think the shard is failed finally shard.setStatus(JobInstanceShardStatus.FAILED.value()); jobInstanceShardDao.save(shard); jobInstanceShardDao.addShard2StatusSet(shard.getInstanceId(), shard.getId(), JobInstanceShardStatus.FAILED); throw new ShardOperateException(ShardOperateRespCode.SHARD_PULL_COUNT_EXCEED); } // add the shard to client's running set jobInstanceShardDao.addShard2ClientRunningSet(client, shardId); // add the shard to running shard jobInstanceShardDao.addShard2StatusSet(jobInstanceId, shardId, JobInstanceShardStatus.RUNNING); // update the shard shard.setPullCount(shard.getPullCount() + 1); shard.setPullTime(new Date()); shard.setStatus(JobInstanceShardStatus.RUNNING.value()); shard.setPullClient(client); if (!jobInstanceShardDao.save(shard)){ throw new ShardOperateException(ShardOperateRespCode.SHARD_PULL_FAILED); } return shard; } /** * Return the shard * @param jobInstanceId the job instance id * @param shardId the shard id * @param client the client * @return return true if return successfully, or false */ public Boolean returnShard(Long jobInstanceId, Long shardId, String client) { JobInstanceShard shard = checkShardStatus(shardId); // reset the shard shard.setStatus(JobInstanceShardStatus.NEW.value()); shard.setPullClient(null); shard.setPullTime(null); shard.setUtime(new Date()); // return the shard to shards set jobInstanceShardDao.returnShard2NewShardsSet(jobInstanceId, shardId); // remove the shard from running set jobInstanceShardDao.removeShardFromStatusSet(jobInstanceId, shardId, JobInstanceShardStatus.RUNNING); // remove the shard from client's running set jobInstanceShardDao.removeShardFromClientRunningShards(client, shardId); return jobInstanceShardDao.save(shard); } /** * Finish one shard * @param shardFinishDto the shard finish dto * @return return true if finish successfully, or false */ public Boolean finishShard(ShardFinishDto shardFinishDto) { // check shard Long shardId = shardFinishDto.getShardId(); JobInstanceShard shard = checkShardStatus(shardId); Long instanceId = shardFinishDto.getInstanceId(); // add the shard to success or fail set if (shardFinishDto.getSuccess()){ jobInstanceShardDao.addShard2StatusSet(instanceId, shardId, JobInstanceShardStatus.SUCCESS); } else { jobInstanceShardDao.addShard2StatusSet(instanceId, shardId, JobInstanceShardStatus.FAILED); } // remove the shard from running set jobInstanceShardDao.removeShardFromStatusSet(instanceId, shardId, JobInstanceShardStatus.RUNNING); // remove the shard from client's running set jobInstanceShardDao.removeShardFromClientRunningShards(shardFinishDto.getClient(), shardId); // update the shard if(shardFinishDto.getSuccess()){ shard.setStatus(JobInstanceShardStatus.SUCCESS.value()); } else { shard.setStatus(JobInstanceShardStatus.FAILED.value()); shard.setCause(shardFinishDto.getCause()); } shard.setStartTime(shardFinishDto.getStartTime()); shard.setEndTime(shardFinishDto.getEndTime()); shard.setFinishClient(shardFinishDto.getClient()); shard.setUtime(new Date()); return jobInstanceShardDao.save(shard); } private JobInstanceShard checkShardStatus(Long shardId){ JobInstanceShard shard = jobInstanceShardDao.findById(shardId); if (shard == null){ Logs.warn("The job shard(id={}) doesn't exist when finish.", shardId); throw new ShardOperateException(ShardOperateRespCode.SHARD_NOT_EXIST); } JobInstanceShardStatus shardStatus = JobInstanceShardStatus.from(shard.getStatus()); if (shardStatus == JobInstanceShardStatus.SUCCESS || shardStatus == JobInstanceShardStatus.FAILED){ Logs.warn("The job shard(id={})'s status is final: {}", shardId, shardStatus); throw new ShardOperateException(ShardOperateRespCode.SHARD_FINAL); } return shard; } }