mirror of
https://codeup.aliyun.com/67c68d4e484ca2f0a13ac3c1/ydc/jsowell-charger-web.git
synced 2026-07-23 07:31:51 +08:00
新增待办过期和历史归档任务
This commit is contained in:
19
docs/sql/sys_todo_maintenance_job.sql
Normal file
19
docs/sql/sys_todo_maintenance_job.sql
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
-- 待办任务过期与历史归档定时任务
|
||||||
|
-- 默认每天 02:30 执行;归档保留天数通过 todo.retention-days 配置,最少保留 180 天。
|
||||||
|
|
||||||
|
INSERT INTO sys_job (
|
||||||
|
job_name, job_group, invoke_target, cron_expression,
|
||||||
|
misfire_policy, concurrent, status, create_by, create_time, remark
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
'待办过期与历史归档', 'SYSTEM', 'todoTaskMaintenanceTask.maintain()', '0 30 2 * * ?',
|
||||||
|
'3', '1', '0', 'system', sysdate(), '过期待处理任务并逻辑归档至少180天前的终态任务'
|
||||||
|
FROM DUAL
|
||||||
|
WHERE NOT EXISTS (
|
||||||
|
SELECT 1 FROM sys_job
|
||||||
|
WHERE invoke_target = 'todoTaskMaintenanceTask.maintain()'
|
||||||
|
);
|
||||||
|
|
||||||
|
SELECT job_id, job_name, invoke_target, cron_expression, status
|
||||||
|
FROM sys_job
|
||||||
|
WHERE invoke_target = 'todoTaskMaintenanceTask.maintain()';
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package com.jsowell.quartz.task;
|
||||||
|
|
||||||
|
import com.jsowell.system.domain.dto.TodoTaskMaintenanceResult;
|
||||||
|
import com.jsowell.system.service.TodoTaskMaintenanceService;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
class TodoTaskMaintenanceTaskTest {
|
||||||
|
@Test
|
||||||
|
void maintain_shouldDelegateToMaintenanceService() {
|
||||||
|
TodoTaskMaintenanceService service = mock(TodoTaskMaintenanceService.class);
|
||||||
|
TodoTaskMaintenanceTask task = new TodoTaskMaintenanceTask();
|
||||||
|
setField(task, "todoTaskMaintenanceService", service);
|
||||||
|
when(service.maintain()).thenReturn(new TodoTaskMaintenanceResult(1, 2, new Date()));
|
||||||
|
|
||||||
|
task.maintain();
|
||||||
|
|
||||||
|
verify(service).maintain();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void setField(Object target, String fieldName, Object value) {
|
||||||
|
try {
|
||||||
|
Field field = TodoTaskMaintenanceTask.class.getDeclaredField(fieldName);
|
||||||
|
field.setAccessible(true);
|
||||||
|
field.set(target, value);
|
||||||
|
} catch (Exception exception) {
|
||||||
|
throw new RuntimeException(exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
package com.jsowell.system.service;
|
||||||
|
|
||||||
|
import com.jsowell.system.domain.dto.TodoTaskMaintenanceResult;
|
||||||
|
import com.jsowell.system.mapper.SysTodoTaskMapper;
|
||||||
|
import com.jsowell.system.service.impl.TodoTaskMaintenanceServiceImpl;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
class TodoTaskMaintenanceServiceImplTest {
|
||||||
|
@Test
|
||||||
|
void maintain_shouldExpireAndKeepAtLeast180Days() {
|
||||||
|
SysTodoTaskMapper mapper = mock(SysTodoTaskMapper.class);
|
||||||
|
TodoTaskMaintenanceServiceImpl service = new TodoTaskMaintenanceServiceImpl();
|
||||||
|
setField(service, "todoTaskMapper", mapper);
|
||||||
|
setField(service, "retentionDays", 30);
|
||||||
|
when(mapper.expireDueTasks(any(Date.class), any(String.class))).thenReturn(2);
|
||||||
|
when(mapper.archiveTerminalTasks(any(Date.class), any(String.class))).thenReturn(3);
|
||||||
|
|
||||||
|
TodoTaskMaintenanceResult result = service.maintain();
|
||||||
|
|
||||||
|
assertEquals(2, result.getExpiredCount());
|
||||||
|
assertEquals(3, result.getArchivedCount());
|
||||||
|
ArgumentCaptor<Date> nowCaptor = ArgumentCaptor.forClass(Date.class);
|
||||||
|
ArgumentCaptor<Date> archiveCaptor = ArgumentCaptor.forClass(Date.class);
|
||||||
|
verify(mapper).expireDueTasks(nowCaptor.capture(), any(String.class));
|
||||||
|
verify(mapper).archiveTerminalTasks(archiveCaptor.capture(), any(String.class));
|
||||||
|
long retentionDays = (nowCaptor.getValue().getTime() - archiveCaptor.getValue().getTime())
|
||||||
|
/ (24L * 60 * 60 * 1000);
|
||||||
|
assertTrue(retentionDays >= 179);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void setField(Object target, String fieldName, Object value) {
|
||||||
|
try {
|
||||||
|
Field field = TodoTaskMaintenanceServiceImpl.class.getDeclaredField(fieldName);
|
||||||
|
field.setAccessible(true);
|
||||||
|
field.set(target, value);
|
||||||
|
} catch (Exception exception) {
|
||||||
|
throw new RuntimeException(exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package com.jsowell.quartz.task;
|
||||||
|
|
||||||
|
import com.jsowell.system.domain.dto.TodoTaskMaintenanceResult;
|
||||||
|
import com.jsowell.system.service.TodoTaskMaintenanceService;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 待办过期和历史归档定时任务。
|
||||||
|
*/
|
||||||
|
@Component("todoTaskMaintenanceTask")
|
||||||
|
public class TodoTaskMaintenanceTask {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(TodoTaskMaintenanceTask.class);
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private TodoTaskMaintenanceService todoTaskMaintenanceService;
|
||||||
|
|
||||||
|
public void maintain() {
|
||||||
|
TodoTaskMaintenanceResult result = todoTaskMaintenanceService.maintain();
|
||||||
|
log.info("待办维护任务完成,expiredCount={}, archivedCount={}, archiveBefore={}",
|
||||||
|
result.getExpiredCount(), result.getArchivedCount(), result.getArchiveBefore());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package com.jsowell.system.domain.dto;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 待办维护任务执行结果。
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class TodoTaskMaintenanceResult implements Serializable {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private int expiredCount;
|
||||||
|
private int archivedCount;
|
||||||
|
private Date archiveBefore;
|
||||||
|
}
|
||||||
@@ -6,6 +6,7 @@ import com.jsowell.system.domain.dto.TodoTaskQuery;
|
|||||||
import org.apache.ibatis.annotations.Param;
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 待办任务数据层。
|
* 待办任务数据层。
|
||||||
@@ -73,4 +74,9 @@ public interface SysTodoTaskMapper {
|
|||||||
@Param("updateBy") String updateBy);
|
@Param("updateBy") String updateBy);
|
||||||
|
|
||||||
int hideTodo(@Param("todoId") Long todoId, @Param("updateBy") String updateBy);
|
int hideTodo(@Param("todoId") Long todoId, @Param("updateBy") String updateBy);
|
||||||
|
|
||||||
|
int expireDueTasks(@Param("now") Date now, @Param("updateBy") String updateBy);
|
||||||
|
|
||||||
|
int archiveTerminalTasks(@Param("archiveBefore") Date archiveBefore,
|
||||||
|
@Param("updateBy") String updateBy);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package com.jsowell.system.service;
|
||||||
|
|
||||||
|
import com.jsowell.system.domain.dto.TodoTaskMaintenanceResult;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 待办过期和历史归档维护服务。
|
||||||
|
*/
|
||||||
|
public interface TodoTaskMaintenanceService {
|
||||||
|
TodoTaskMaintenanceResult maintain();
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package com.jsowell.system.service.impl;
|
||||||
|
|
||||||
|
import com.jsowell.common.util.DateUtils;
|
||||||
|
import com.jsowell.system.domain.dto.TodoTaskMaintenanceResult;
|
||||||
|
import com.jsowell.system.mapper.SysTodoTaskMapper;
|
||||||
|
import com.jsowell.system.service.TodoTaskMaintenanceService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 待办过期和历史归档维护服务实现。
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class TodoTaskMaintenanceServiceImpl implements TodoTaskMaintenanceService {
|
||||||
|
private static final int DEFAULT_RETENTION_DAYS = 180;
|
||||||
|
|
||||||
|
@Value("${todo.retention-days:180}")
|
||||||
|
private Integer retentionDays;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private SysTodoTaskMapper todoTaskMapper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public TodoTaskMaintenanceResult maintain() {
|
||||||
|
Date now = DateUtils.getNowDate();
|
||||||
|
int safeRetentionDays = retentionDays == null || retentionDays < DEFAULT_RETENTION_DAYS
|
||||||
|
? DEFAULT_RETENTION_DAYS : retentionDays;
|
||||||
|
int expiredCount = todoTaskMapper.expireDueTasks(now, "todo-maintenance");
|
||||||
|
Date archiveBefore = DateUtils.addDays(now, -safeRetentionDays);
|
||||||
|
int archivedCount = todoTaskMapper.archiveTerminalTasks(archiveBefore, "todo-maintenance");
|
||||||
|
return new TodoTaskMaintenanceResult(expiredCount, archivedCount, archiveBefore);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -287,4 +287,28 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
and del_flag = '0'
|
and del_flag = '0'
|
||||||
</update>
|
</update>
|
||||||
|
|
||||||
|
<update id="expireDueTasks">
|
||||||
|
update sys_todo_task
|
||||||
|
set task_status = 'EXPIRED',
|
||||||
|
completed_time = #{now},
|
||||||
|
active_idempotent_key = null,
|
||||||
|
update_by = #{updateBy},
|
||||||
|
update_time = #{now}
|
||||||
|
where task_status in ('PENDING', 'PROCESSING')
|
||||||
|
and due_time is not null
|
||||||
|
and due_time <= #{now}
|
||||||
|
and del_flag = '0'
|
||||||
|
</update>
|
||||||
|
|
||||||
|
<update id="archiveTerminalTasks">
|
||||||
|
update sys_todo_task
|
||||||
|
set del_flag = '2',
|
||||||
|
active_idempotent_key = null,
|
||||||
|
update_by = #{updateBy},
|
||||||
|
update_time = sysdate()
|
||||||
|
where task_status in ('COMPLETED', 'CANCELLED', 'EXPIRED')
|
||||||
|
and coalesce(completed_time, update_time, create_time) < #{archiveBefore}
|
||||||
|
and del_flag = '0'
|
||||||
|
</update>
|
||||||
|
|
||||||
</mapper>
|
</mapper>
|
||||||
|
|||||||
Reference in New Issue
Block a user