mitao
2024-06-26 884f5c68ac8c738f90f1ca257605cfbb5d7f12db
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
package com.ruoyi.goods.service.async;
 
import com.ruoyi.common.core.constant.SecurityConstants;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.common.redis.service.RedisService;
import com.ruoyi.system.api.constants.DelayTaskEnum;
import com.ruoyi.system.api.domain.DelayTask;
import com.ruoyi.system.api.domain.GoodsGroupPurchase;
import com.ruoyi.system.api.domain.GoodsSeckill;
import com.ruoyi.system.api.feignClient.SysUserClient;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.TimeUnit;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
 
/**
 * @author mitao
 * @date 2024/5/24
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class AsyncMethodService {
 
    private final RedisService redisService;
    private final SysUserClient sysUserClient;
 
    @Async
    @Transactional(rollbackFor = Exception.class)
    public void seckillScheduleTask(List<GoodsSeckill> goodsSeckillList) {
        for (GoodsSeckill goodsSeckill : goodsSeckillList) {
            LocalDateTime startTime = goodsSeckill.getStartTime();
            LocalDateTime endTime = goodsSeckill.getEndTime();
            // 秒杀在一小时内开始
            if (isWithinOneHour(startTime)) {
                Long id = goodsSeckill.getId();
                // 秒杀已经开始
                if (LocalDateTime.now().isAfter(startTime)) {
                    handleStartDelayTask(id, DelayTaskEnum.SECKILL_START_TASK, startTime, 3L);
                } else {
                    Duration duration = Duration.between(LocalDateTime.now(), startTime);
                    handleStartDelayTask(id, DelayTaskEnum.SECKILL_START_TASK, startTime,
                            duration.getSeconds());
                }
                log.info(">>>>>>>>>>>>>>>>>>>>秒杀商品:{} 开始秒杀<<<<<<<<<<<<<<<<<<<<", id);
                // 秒杀结束延时任务
                handleEndDelayTask(id, DelayTaskEnum.SECKILL_END_TASK, endTime);
            }
        }
    }
 
    @Async
    @Transactional(rollbackFor = Exception.class)
    public void groupPurchaseScheduleTask(List<GoodsGroupPurchase> groupPurchaseList) {
        for (GoodsGroupPurchase goodsGroupPurchase : groupPurchaseList) {
            LocalDateTime startTime = goodsGroupPurchase.getStartTime();
            LocalDateTime endTime = goodsGroupPurchase.getEndTime();
            // 团购在一小时内开始
            if (isWithinOneHour(startTime)) {
                Long id = goodsGroupPurchase.getId();
                // 团购已经开始,三秒后执行
                if (LocalDateTime.now().isAfter(startTime)) {
                    handleStartDelayTask(id, DelayTaskEnum.GROUP_PURCHASES_START_TASK, startTime,
                            3L);
                } else {
                    Duration duration = Duration.between(LocalDateTime.now(), startTime);
                    handleStartDelayTask(id, DelayTaskEnum.GROUP_PURCHASES_START_TASK, startTime,
                            duration.getSeconds());
                }
                // 团购结束延时任务
                handleEndDelayTask(id, DelayTaskEnum.GROUP_PURCHASES_END_TASK, endTime);
            }
        }
    }
    
    private boolean isWithinOneHour(LocalDateTime startTime) {
        LocalDateTime checkTime = LocalDateTime.now().plusHours(1);
        return checkTime.isAfter(startTime);
    }
 
    private void handleEndDelayTask(Long id, DelayTaskEnum delayTaskEnum, LocalDateTime endTime) {
        String endTaskKey = delayTaskEnum.getCode() + "-" + id;
        DelayTask endDelayTask = sysUserClient.getDelayTask(
                endTaskKey, SecurityConstants.INNER).getData();
        // 如果延时任务为空,创建延时任务控制活动定时开始和结束
        Duration duration = Duration.between(LocalDateTime.now(), endTime);
        if (StringUtils.isNull(endDelayTask)) {
            createEndDelayTask(endTime, endTaskKey, duration);
        } else {
            if (!endDelayTask.getExecuteTime().isEqual(endTime)) {
                sysUserClient.deleteDelayTask(endTaskKey,
                        SecurityConstants.INNER);
                redisService.deleteObject(endTaskKey);
                createEndDelayTask(endTime, endTaskKey, duration);
            }
        }
        log.info(">>>>>>>>>>>>>>>>>>>>延时任务{}执行了<<<<<<<<<<<<<<<<<<<<", endTaskKey);
    }
 
    private void createEndDelayTask(LocalDateTime endTime, String seckillEndTaskKey,
            Duration duration) {
        DelayTask endDelayTask;
        redisService.setCacheObject(
                seckillEndTaskKey,
                endTime, duration.getSeconds(), TimeUnit.SECONDS);
        endDelayTask = new DelayTask();
        endDelayTask.setDelFlag(0);
        endDelayTask.setCreateTime(LocalDateTime.now());
        endDelayTask.setExecuteTime(endTime);
        endDelayTask.setRedisKey(seckillEndTaskKey);
        sysUserClient.addDelayTask(endDelayTask, SecurityConstants.INNER);
    }
 
    private void handleStartDelayTask(Long id, DelayTaskEnum delayTaskEnum, LocalDateTime startTime,
            Long timeout) {
        String startTaskKey = delayTaskEnum.getCode() + "-" + id;
        //查询延时任务
        DelayTask startDelayTask = sysUserClient.getDelayTask(
                startTaskKey, SecurityConstants.INNER).getData();
        if (StringUtils.isNull(startDelayTask)) {
            startDelayTask = new DelayTask();
            startDelayTask.setDelFlag(0);
            startDelayTask.setCreateTime(LocalDateTime.now());
            startDelayTask.setExecuteTime(LocalDateTime.now().plusSeconds(timeout));
            startDelayTask.setRedisKey(
                    startTaskKey);
            sysUserClient.addDelayTask(startDelayTask, SecurityConstants.INNER);
        } else {
            if (!startDelayTask.getExecuteTime().isEqual(startTime)) {
                sysUserClient.deleteDelayTask(
                        startTaskKey, SecurityConstants.INNER);
                redisService.deleteObject(
                        startTaskKey);
                startDelayTask.setDelFlag(0);
                startDelayTask.setCreateTime(LocalDateTime.now());
                startDelayTask.setExecuteTime(LocalDateTime.now().plusSeconds(timeout));
                startDelayTask.setRedisKey(
                        startTaskKey);
                sysUserClient.addDelayTask(startDelayTask, SecurityConstants.INNER);
            }
        }
        redisService.setCacheObject(startTaskKey, startTime, timeout, TimeUnit.SECONDS);
        log.info(">>>>>>>>>>>>>>>>>>>>延时任务{}执行了<<<<<<<<<<<<<<<<<<<<", startTaskKey);
    }
}