A simple message queue (support delaying a message in support of persistence, the only guarantee consumer)

The main message manager object:

package com.rynk.mugua.trading.biz.service.impl;

import java.util.concurrent.DelayQueue;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.rynk.commons.entity.QueueMessage;
import com.rynk.mugua.trading.biz.commons.RedisKeyResolver;
import com.rynk.mugua.trading.biz.commons.lock.DistributedLockHandler;
import com.rynk.mugua.trading.biz.eth.DelayedTack;

import lombok.extern.slf4j.Slf4j;
/**
 * Delay Message Administrator
 * @author ZHANGYUKUNUP
 *
 */
@Component
@ Slf4j
public class QueueManger {
	
	MessagePersistent messagePersistent;
	
	/**
	 * Message Queuing delay
	 */
	private DelayQueue<DelayedTack> dQueue = new DelayQueue<>();
	
	/**
	 * Message task processing thread
	 */
	private Thread taskThread;
	
	@Autowired
	DistributedLockHandler lock;
	
	
	public QueueManger() {
		taskThread = new TaskThread();
		taskThread.start();
	}
	
	/**
	 * Task thread
	 * @author ZHANGYUKUNUP
	 *
	 */
	class TaskThread extends Thread{
		
		@Override
		public void run() {
			while (true) {
				try {
					DelayedTack delayedTack = dQueue.take();
					QueueMessage queueMessage = delayedTack.getQueueMessage();
					if( queueMessage == null ) {
						return ;
					}
					
					// add a simple lock to ensure that messages are not repeated consumption (need to unlock the front to ensure that the data is submitted to the database, whether the person will be out of synchronization problems, that can not have a greater range of matters parcel of the current method)
					if(  lock.tryLock(  RedisKeyResolver.getMsgrKey( queueMessage.getId() )    ) ) {
						
						// If this message is normal consumption, consumption of success so long mark, if abnormal consumption, so long retry the news
						try {
							if( QueueManger.this.messageDispense(delayedTack.getQueueMessage())  ) {
								messagePersistent.succeed( queueMessage );
							}else {
								QueueManger.this.reTry( queueMessage  );
							}
						}catch (Exception e) {
							e.printStackTrace ();
							QueueManger.this.reTry(queueMessage);
						}finally {
							lock.unLock( RedisKeyResolver.getMsgrKey( queueMessage.getId() )    );
						}
					}
				} catch (Exception e) {
					e.printStackTrace ();
				}
			}
		}
		
	}
	
	
	
	
	/**
	 * Retry
	 * @Param queueMessage
	 */
	protected void reTry(QueueMessage queueMessage) {
		messagePersistent.reTry(queueMessage);
	}



	/**
	 * Distribution message
	 * @Param queueMessage
	 */
	protected boolean messageDispense(QueueMessage queueMessage) {
		
		return messagePersistent.consume(queueMessage);
	}

	/**
	 * Add a delay message
	 * @Param delayedTack
	 */
	public void put(DelayedTack delayedTack) {
		dQueue.put(delayedTack);
	}
	
	/**
	 * The number of queries untreated delay news
	 * @return
	 */
	public int size() {
		return dQueue.size();
	}
	
	/**
	 * Message processing thread survival status
	 * @return
	 */
	public boolean isAlive() {
		return taskThread.isAlive();
	}
	

}

 

Message object:

package com.rynk.commons.entity;

import java.util.Date;

import org.springframework.data.mongodb.core.mapping.Document;

com.rynk.commons.entity.em.QueueMessageType amount;
com.rynk.commons.entity.em.TransferRecordStatus amount;
com.rynk.commons.util.SnGeneratorUtil amount;

import lombok.Data;

@Data
@Document(collection = "mg_queue_message")
public class QueueMessage extends BaseEntity {

	/**
	 * Wake-up time
	 */
	private Date awakenDate;
	
	
	/**
	 * Processing status
	 */
	private TransferRecordStatus transferRecordStatus;
	
	
	/**
	 * News body
	 */
	private String  body;
	
	/**
	 * Message body type
	 */
	private QueueMessageType type;
	

	/**
	 * number of retries
	 */
	private Integer tryTimes;
	
	
	/**
	 * Last check time
	 */
	private Date lastCheckDate;
	

	
	
	/**
	 * 
	 * @Param body message body Source Type
	 * @Param type message type
	 * @Param delayed delay
	 * @return
	 */
	public static  QueueMessage newInstance( String  body , QueueMessageType type , long delayed ) {
		QueueMessage item = new QueueMessage();
		item.setId( SnGeneratorUtil.getId().toString() );
		item.setCreateDate(  new Date() );
		item.setDr(false);
		
		item.setTransferRecordStatus( TransferRecordStatus.WAIT );
		item.setTryTimes(1);
		item.setBody(body);
		item.setType(type);
		item.setAwakenDate( new Date( System.currentTimeMillis()+delayed ));
		item.setLastCheckDate( item.getAwakenDate() );
		
		return item;
	}

	
}

  

 

Redis-based distributed lock objects:

 

package com.rynk.mugua.trading.biz.commons.lock;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;

import java.text.SimpleDateFormat;
import java.util.Date;
java.util.concurrent.TimeUnit import;

/**
 * Distributed Lock
 *
 * @Author ZHANGYUKUN
 *
 */
@Component
public class DistributedLockHandler {

	private static final Logger logger = LoggerFactory.getLogger(DistributedLockHandler.class);

	/**
	 * Maximum lock hold time (ms)
	 */
	private final static long LOCK_EXPIRE = 30 * 1000L;

	/**
	 * Attempt to acquire a lock interval (ms)
	 */
	private final static long LOCK_TRY_INTERVAL = 30L;

	/**
	 * Get the maximum lock wait time (ms)
	 */
	private final static long LOCK_TRY_TIMEOUT = 20 * 1000L;

	@Resource// (name = "customRedisTemplate")
	private RedisTemplate<String, String> template;

	/**
	 * Try to obtain Distributed Lock
	 *
	 * @Param lockKey
	 * Lock name
	 * @Return true has been locked, false acquire the lock failure
	 */
	public boolean tryLock(String lockKey) {
		return getLock(lockKey, LOCK_TRY_TIMEOUT, LOCK_TRY_INTERVAL, LOCK_EXPIRE);
	}

	/**
	 * Distributed attempt to acquire a lock (not automatically release the lock)
	 *
	 * @Param lockKey
	 * Lock name
	 * @Return true has been locked, false acquire the lock failure
	 */
	public boolean tryLockNotAutoRelease(String lockKey) {
		return getLock(lockKey, LOCK_TRY_TIMEOUT, LOCK_TRY_INTERVAL, -1);
	}

	/**
	 * Try to obtain Distributed Lock
	 *
	 * @Param lockKey
	 * Lock name
	 * @param timeout
	 * Get the maximum waiting time lock
	 * @Return true has been locked, false acquire the lock failure
	 */
	public boolean tryLock(String lockKey, long timeout) {
		return getLock(lockKey, timeout, LOCK_TRY_INTERVAL, LOCK_EXPIRE);
	}

	/**
	 * Distributed attempt to acquire a lock (not automatically release the lock)
	 *
	 * @Param lockKey
	 * Lock name
	 * @param timeout
	 * Get the maximum waiting time lock
	 * @Return true has been locked, false acquire the lock failure
	 */
	public boolean tryLockNotAutoRelease(String lockKey, long timeout) {
		return getLock(lockKey, timeout, LOCK_TRY_INTERVAL, -1);
	}

	/**
	 * Try to obtain Distributed Lock
	 *
	 * @Param lockKey
	 * Lock name
	 * @param timeout
	 * Get the maximum waiting time lock
	 * @Param tryInterval
	 * Get a lock attempt time interval
	 * @Return true has been locked, false acquire the lock failure
	 */
	public boolean tryLock(String lockKey, long timeout, long tryInterval) {
		return getLock(lockKey, timeout, tryInterval, LOCK_EXPIRE);
	}

	/**
	 * Try to obtain a distributed lock (lock not released)
	 *
	 * @Param lockKey
	 * Lock name
	 * @param timeout
	 * Get the maximum waiting time lock
	 * @Param tryInterval
	 * Get a lock attempt time interval
	 * @Return true has been locked, false acquire the lock failure
	 */
	public boolean tryLockNotAutoRelease(String lockKey, long timeout, long tryInterval) {
		return getLock(lockKey, timeout, tryInterval, -1);
	}

	/**
	 * Try to obtain Distributed Lock
	 *
	 * @Param lockKey
	 * Lock name
	 * @param timeout
	 * Get the maximum waiting time lock
	 * @Param tryInterval
	 * Get a lock attempt time interval
	 * @param lockExpireTime
	 * The maximum lock holding time
	 * @Return true has been locked, false acquire the lock failure
	 */
	public boolean tryLock(String lockKey, long timeout, long tryInterval, long lockExpireTime) {
		return getLock(lockKey, timeout, tryInterval, lockExpireTime);
	}

	/**
	 * Get Distributed Lock
	 *
	 * @Param lockKey
	 * Lock name
	 * @param timeout
	 * Get the maximum waiting time lock
	 * @Param tryInterval
	 * Get a lock attempt time interval
	 * @param lockExpireTime
	 * The maximum lock holding time
	 * @Return true has been locked, false acquire the lock failure
	 */
	public boolean getLock(String lockKey, long timeout, long tryInterval, long lockExpireTime) {
		try {
			if (StringUtils.isEmpty(lockKey)) {
				return false;
			}
			long startTime = System.currentTimeMillis();
			do {
				ValueOperations<String, String> ops = template.opsForValue();
				SimpleDateFormat sd = new SimpleDateFormat("yyyy-mm-dd HH:mm:ss");
				if (ops.setIfAbsent(lockKey, sd.format(new Date())  )) {
					if (lockExpireTime > 0) {
						template.expire(lockKey, lockExpireTime, TimeUnit.MILLISECONDS);
					}
					return true;
				}
				Thread.sleep(tryInterval);
			} while (System.currentTimeMillis() - startTime < timeout);
		} catch (InterruptedException e) {
			logger.error(e.getMessage());
			return false;
		}
		return false;
	}

	/**
	 * Release the lock
	 *
	 * @Param lockKey
	 */
	public void unLock(String lockKey) {
		if (!StringUtils.isEmpty(lockKey)) {
			template.delete(lockKey);
		}
	}

}

  

 

Task objects Delay: delay for dispensing message

 

package com.rynk.mugua.trading.biz.eth;

import java.util.concurrent.Delayed;
java.util.concurrent.TimeUnit import;

import com.rynk.commons.entity.QueueMessage;
import com.rynk.mugua.trading.biz.mqMessage.ChainMessageDelayTimeLevel;

/**
 * Delay task
 * @Author zhangyukun
 *
 */
public class DelayedTack implements Delayed{
	/**
	 * Time of execution
	 */
	Long  runTime;
	
	/**
	 * Message Object
	 */
	QueueMessage queueMessage;
	
	
	public QueueMessage getQueueMessage() {
		return queueMessage;
	}

	public void setQueueMessage(QueueMessage queueMessage) {
		this.queueMessage = queueMessage;
	}


	/**
	 * 
	 * @Param delay delay milliseconds
	 * @Param queueMessage message body
	 */
	public DelayedTack( QueueMessage queueMessage  ) {
		
		if( queueMessage.getTryTimes() == 1  ) {
			this.runTime = queueMessage.getAwakenDate().getTime();
		}else {
			this.runTime =System.currentTimeMillis() + ChainMessageDelayTimeLevel.getDelayTimeLevel( queueMessage.getTryTimes() )*1000 ;
		}
		
		this.queueMessage = queueMessage;
	}
	
	@Override
	public long getDelay(TimeUnit unit) {
		return unit.convert( runTime - System.currentTimeMillis() , TimeUnit.MILLISECONDS);
	}

	@Override
	public int compareTo(Delayed o) {
		return (int) (this.getDelay(TimeUnit.MILLISECONDS) -o.getDelay(TimeUnit.MILLISECONDS));
	}
	


}

  

Object persistence messages: three ways to achieve it wants to do their own

package com.rynk.mugua.trading.biz.service.impl;

import com.rynk.commons.entity.QueueMessage;

public class MessagePersistent {
	
	/**
	 * Business logic to process the news consumption
	 * @Param queueMessage
	 * @return
	 */
	public boolean consume(QueueMessage queueMessage) {
		return false;
	}
	
	/**
	 * This message has been labeled normal consumption
	 * @Param queueMessage
	 */
	public void succeed(QueueMessage queueMessage) {
		
	}
	
	/**
	 * Retry message (status flag of the database, and then put it back into the queue delay)
	 * @Param queueMessage
	 */
	public void reTry(QueueMessage queueMessage) {
		
		
	}

}

  

Guess you like

Origin www.cnblogs.com/cxygg/p/12162878.html