定时任务 + queue队列处理

本文介绍了一个用于处理用户行为并更新经验值的队列机制,该机制通过不同的操作键值来区分用户的不同行为,并据此更新用户的等级和荣誉。具体包括收藏、点赞、评论等多种互动行为。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

package poseidon.web.muses.db;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;


import poseidon.web.muses.db.userlevel.service.LevelHornorQueueService;


/**
 * 处理更新经验的定时任务
 * 
 * @author hulufeng
 * 
 */
@Component
public class LevelHornorQueueHandlerTask {
private static Logger log = LoggerFactory.getLogger(LevelHornorQueueHandlerTask.class);

@Autowired
LevelHornorQueueService levelQueueService;

// 一分钟执行一次
@Scheduled(cron = "0/60 * * * * *")
public void execute() {
log.debug("execute LevelHonorQueueHandlerTask");
try {
levelQueueService.handleElements();
} catch (Exception e) {
log.error("LevelHonorQueueHandlerTask", e);
}

}

}




队列:

package poseidon.web.muses.db.userlevel.serviceImpl;


import java.util.Map;
import java.util.concurrent.LinkedBlockingQueue;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;


import poseidon.web.muses.db.act.model.ActModel;
import poseidon.web.muses.db.common.lucene.model.QueueElement;
import poseidon.web.muses.db.global.GlobalUserLevel;
import poseidon.web.muses.db.tribe.model.TribePostModel;
import poseidon.web.muses.db.user.model.UserModel;
import poseidon.web.muses.db.userhonor.service.AchieveHonorRuleService;
import poseidon.web.muses.db.userlevel.model.UserExperienceHisModel;
import poseidon.web.muses.db.userlevel.service.ActRuleService;
import poseidon.web.muses.db.userlevel.service.LevelHornorQueueService;
import poseidon.web.muses.db.userlevel.service.LoginRuleService;
import poseidon.web.muses.db.userlevel.service.TribeRuleService;
import poseidon.web.muses.db.userlevel.service.UserLevelService;


/**
 * 经验更新队列实现类
 * 
 * @author hulufeng 20160727
 * 
 */
@Service
public class LevelHonorQueueServiceImpl implements LevelHornorQueueService {
private final static Logger log = LoggerFactory
.getLogger(LevelHonorQueueServiceImpl.class);


@Autowired
private UserLevelService userLevelService;
@Autowired
private ActRuleService actRuleService;
@Autowired
private LoginRuleService loginRuleService;

@Autowired
private AchieveHonorRuleService achieveHonorRuleService;
    @Autowired
    private TribeRuleService tribeRuleService;
/**
* 同步队列
*/
private static final LinkedBlockingQueue<QueueElement> linkQueue = new LinkedBlockingQueue<QueueElement>();


@Override
public void addElement(Map<String,Object> map) throws Exception {
QueueElement el = new QueueElement();
el.setElement(map);
linkQueue.offer(el);
}

/**
* 处理经验更新队列中的每一个元素
*/
@Override
public void handleElements() {
try {
while (!linkQueue.isEmpty()) {
QueueElement el = linkQueue.poll();
Map<String, Object> map = (Map<String, Object>) el.getElement();

Integer kid = Integer.parseInt(map.get("kid").toString());
Long aid = Long.parseLong((map.get("aid") == null ? 0 : map.get("aid")).toString() );
Long uid = Long.parseLong((map.get("uid") == null ? 0 : map.get("uid")).toString() );
Long operuid = Long.parseLong((map.get("operuid") == null ? 0 : map.get("operuid")).toString() );
UserExperienceHisModel userExperienceHisModel = new UserExperienceHisModel();
if(map.get("model") != null){//如果传了UserExperienceHisModel历史经验表
userExperienceHisModel = (UserExperienceHisModel) map.get("model");
}
ActModel actModel = new ActModel();
UserModel userModel = new UserModel();

log.debug("kid = " + kid);

switch (kid) {
case GlobalUserLevel.ActOperationKeys.ACT_FAVORITE://收藏活动
userLevelService.favoriteAct(aid, uid);
break;
case GlobalUserLevel.ActOperationKeys.ACT_LIKE://点赞活动
userLevelService.likeAct(aid, uid);
achieveHonorRuleService.likeAct(aid, uid);
break;
case GlobalUserLevel.ActOperationKeys.COMMENT_ACT://评论活动
Integer score1 = Integer.parseInt(map.get("score1").toString());
Integer score2 = Integer.parseInt(map.get("score2").toString());
userLevelService.commentAct(aid, uid, score1, score2);
achieveHonorRuleService.commentAct(aid, uid, score1, score2);
break;
case GlobalUserLevel.ActOperationKeys.ACT_BE_JOIN://确认参加活动
userLevelService.joinAct(aid, uid);
achieveHonorRuleService.joinAct(uid);
break;
case GlobalUserLevel.ActOperationKeys.USER_BE_WATCH://被关注
userLevelService.watchUser(uid,operuid);
break;
case GlobalUserLevel.UserSettingKeys.ADD_MEMBER://加入部落
tribeRuleService.activity1(map);//更新经验
            achieveHonorRuleService.achieve3(map);//更新勋章
break;
case GlobalUserLevel.UserSettingKeys.PUBLISH_POST://发表话题
TribePostModel tribePostModel = (TribePostModel) map.get("tribePost");
userLevelService.publishPost(tribePostModel);//新增用户经验
           achieveHonorRuleService.achieve4(tribePostModel, tribePostModel.getUid());//新增用户勋章
break;
case GlobalUserLevel.UserSettingKeys.LIKE_POST://点赞话题
Long topicId = Long.parseLong(map.get("topicId").toString());
userLevelService.likeTribePost(topicId,uid);//新增用户经验
achieveHonorRuleService.likeTribePost(topicId, uid);
break;
case GlobalUserLevel.UserSettingKeys.REPLY_POST://评论话题
Long topicId1 = Long.parseLong(map.get("topicId").toString());
userLevelService.replyTribePost(topicId1,uid);//新增用户经验
break;
case GlobalUserLevel.UserSettingKeys.FAVORITE_POST://收藏话题
Long topicId2 = Long.parseLong(map.get("topicId").toString());
userLevelService.favoriteTribePost(topicId2,uid);//新增用户经验
break;
case GlobalUserLevel.PublishActKeys.PUBLISH_FREEACT://发布免费活动
actModel = (ActModel) map.get("actModel");
actRuleService.activity1(actModel, operuid);//新增用户经验
achieveHonorRuleService.achieve1(actModel, operuid);
break;
case GlobalUserLevel.PublishActKeys.PUBLISH_FEEACT://发布收费活动
actModel = (ActModel) map.get("actModel");
actRuleService.activity2(actModel, operuid);//新增用户经验
achieveHonorRuleService.achieve1(actModel, operuid);
break;
case GlobalUserLevel.LoginTimesKeys.ONETIME_FIRSTDAY://登录
userModel = (UserModel) map.get("userModel");
loginRuleService.activity1(userModel);//新增用户经验
break;
case GlobalUserLevel.UserCertifyKeys.CERTIFY_VIP://认证VIP
case GlobalUserLevel.UserCertifyKeys.CERTIFY_CAR_OWNER://认证车主
case GlobalUserLevel.UserCertifyKeys.CERTIFY_CHIEF://认证酋长
case GlobalUserLevel.UserCertifyKeys.CERTIFY_SERVICE_BUSINESS://认证线路服务商
userLevelService.saveUserExperienceHis(userExperienceHisModel);//新增用户经验
achieveHonorRuleService.userCertify(uid,operuid);//勋章
break;
case GlobalUserLevel.UserSettingKeys.BIND_MOBILE://绑定手机
case GlobalUserLevel.UserSettingKeys.BIND_QQ://绑定QQ
case GlobalUserLevel.UserSettingKeys.BIND_EMAIL://绑定邮箱
case GlobalUserLevel.UserSettingKeys.BIND_SINA://绑定新浪
case GlobalUserLevel.UserSettingKeys.BIND_WX://绑定微信
case GlobalUserLevel.UserSettingKeys.UPLOAD_COVER://上传封面
case GlobalUserLevel.UserSettingKeys.UPLOAD_HEAD://上传头像
case GlobalUserLevel.UserSettingKeys.USER_SIGN://个新签名
case GlobalUserLevel.UserSettingKeys.AUDIT_TRIBE://部落审核
userLevelService.saveUserExperienceHis(userExperienceHisModel);//新增用户经验
break;

}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}



使用:


                    try {
                    Map<String,Object> paramMap = new HashMap<String,Object>();
                    paramMap.put("kid", GlobalUserLevel.ActOperationKeys.ACT_FAVORITE);
        paramMap.put("aid", id);
        paramMap.put("uid", uid);
    levelQueueService.addElement(paramMap);
    } catch (Exception e) {
    log.debug("收藏经验添加失败");
    e.printStackTrace();
    }



<think>嗯,用户想了解如何通过定时任务实现延迟队列,特别是方法和技术方案。首先,我需要回忆一下之前关于Redis和延迟队列的知识。根据提供的引用内容,特别是引用[1]和引用[2],提到Zset结合定时任务的方法。用户可能已经知道Redis的Zset结构可以用来存储带有分数的任务,分数代表执行时间,定时任务定期扫描并取出到期的任务进行处理。 接下来,我需要分解实现步骤。首先,存储任务到Zset,用时间戳作为分数。然后,定时任务如何设计?可能需要每隔一定时间(比如每秒)轮询一次,查询当前时间之前的任务。然后处理这些任务,比如移出队列并执行。 还要考虑技术实现细节,比如使用什么语言,这里可能以Python为例,但用户可能需要更通用的方法。不过用户提供的示例中有Python代码,可能更倾向于展示具体代码。但需要确保代码正确,比如使用zadd和zrangebyscore命令,以及使用Lua脚本保证原子性。 另外,根据引用[1]提到的缺点,比如没有重试机制,延迟时间固定。在回答中需要提到这些局限性,可能还要补充一些优化方法,比如动态调整定时任务的间隔,或者引入重试机制,或者结合其他方案如消息队列的延迟功能。 用户可能还关心实际应用中的问题,比如性能问题,当任务量很大时,频繁扫描Zset可能影响性能。这时候分片或者使用多个Zset可能是一种解决方案。此外,分布式环境下如何处理竞争条件,比如多个定时任务实例同时触发扫描,可能需要分布式锁,但引用中没有提到,可能需要根据经验补充。 还要注意引用中的内容,引用[3]提到Topic的概念,可能需要将不同类型的任务分到不同的Topic中,即不同的Zset键,这样消费者可以订阅不同的主题,提高系统的可扩展性。 最后,总结步骤时,要明确步骤顺序,确保逻辑清晰。同时,比较定时任务方案的优缺点,让用户了解适用场景,比如适合小规模任务,不适合高精度或大规模延迟任务。可能还需要提到其他替代方案,如使用RocketMQ的延迟消息,或者RabbitMQ的插件,但用户的问题是针对定时任务实现的,所以重点在Redis的方案。 需要检查是否所有要点都覆盖到了:存储结构、定时任务轮询、任务处理、原子性操作、优缺点分析、优化方法。可能还需要示例代码,如Python或Java的实现片段,但用户提供的示例中用了Python,所以可能继续用Python展示。 最后,生成相关问题,引导用户进一步思考,比如性能优化、重试机制、与其他方案的对比等。确保问题与当前主题相关,帮助用户深入理解。</think>### 通过定时任务实现延迟队列的方法及技术方案 #### 1. 核心思路 **延迟队列**的核心需求是将任务延迟到指定时间触发。通过**定时任务+有序集合(如Redis Zset)**组合实现: - **Zset存储任务**:将任务与执行时间戳关联,时间戳作为Zset的`score`,任务内容作为`value`[^2][^3]。 - **定时任务轮询**:通过定时任务周期性扫描Zset,拉取当前时间已到期的任务并执行[^1]。 --- #### 2. 具体实现步骤 ##### (1) 存储延迟任务 将任务添加到Redis Zset中,`score`为任务的执行时间戳(单位通常为秒或毫秒),`value`为任务标识或序列化后的任务数据。 ```python import redis r = redis.Redis() def add_delayed_job(job_id, execute_time): r.zadd("delayed_queue", {job_id: execute_time}) ``` ##### (2) 定时任务扫描到期任务 定时任务(如每隔1秒)查询Zset中`score`小于等于当前时间戳的任务,表示这些任务已到期。 ```python import time def poll_delayed_jobs(): current_time = int(time.time() * 1000) # 毫秒时间戳 jobs = r.zrangebyscore("delayed_queue", 0, current_time) # 移除已拉取的任务(需原子操作) r.zremrangebyscore("delayed_queue", 0, current_time) return jobs ``` ##### (3) 处理任务 将拉取的任务发送到实际的任务队列(如Redis List或RabbitMQ),由消费者处理。 ```python def process_jobs(): jobs = poll_delayed_jobs() for job in jobs: r.lpush("ready_queue", job) # 推送到就绪队列 ``` ##### (4) 原子性保障 使用Lua脚本保证`查询`和`删除`操作的原子性,避免多实例竞争导致任务重复执行: ```lua local jobs = redis.call('ZRANGEBYSCORE', KEYS[1], 0, ARGV[1]) if #jobs > 0 then redis.call('ZREMRANGEBYSCORE', KEYS[1], 0, ARGV[1]) end return jobs ``` --- #### 3. 技术方案优缺点 | **优点** | **缺点** | |------------------------------|--------------------------------------------------------------------------| | 实现简单,依赖Redis原生数据结构 | 定时任务间隔影响精度(如1秒间隔则误差≤1秒) | | 天然支持分布式场景 | 大规模任务时频繁扫描Zset可能产生性能压力 | | 可扩展性强(分Topic存储) | 无内置重试机制,需自行实现任务失败处理 | --- #### 4. 优化方向 - **动态调整轮询间隔**:根据任务密度动态缩短或延长扫描间隔。 - **分片存储**:按Topic或时间片拆分多个Zset键,分散查询压力。 - **失败重试**:将处理失败的任务重新插入Zset,并设置新的执行时间戳。 - **多级延迟队列**:结合不同精度的队列(如小时级+分钟级)提升效率。 --- #### 5. 适用场景 - **中小规模延迟任务**(如订单支付超时、定时提醒)。 - **对延迟精度要求不高**(秒级误差可接受)。 - **已有Redis基础设施**,希望快速实现延迟队列。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值