All Downloads are FREE. Search and download functionalities are using the official Maven repository.

pro.jk.ejoker.eventing.EventCommittingContextMailBox Maven / Gradle / Ivy

There is a newer version: 3.0.7.1
Show newest version
package pro.jk.ejoker.eventing;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicBoolean;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import pro.jk.ejoker.common.system.enhance.MapUtilx;
import pro.jk.ejoker.common.system.extension.acrossSupport.EJokerFutureUtil;
import pro.jk.ejoker.common.system.functional.IVoidFunction1;
import pro.jk.ejoker.common.system.helper.Ensure;
import pro.jk.ejoker.common.system.task.context.SystemAsyncHelper;
import pro.jk.ejoker.common.system.wrapper.DiscardWrapper;
import pro.jk.ejoker.eventing.eventingException.DuplicateEventStreamException;

public class EventCommittingContextMailBox {

	private final static Logger logger = LoggerFactory.getLogger(EventCommittingContextMailBox.class);
	
	private final SystemAsyncHelper systemAsyncHelper;
	
	
	private final Queue messageQueue;

	private final Map> aggregateDictDict;
	
	
	private final IVoidFunction1> handler;
	
	private final int batchSize;
	
	private int number;

	private AtomicBoolean onRunning = new AtomicBoolean(false);

	private long lastActiveTime = System.currentTimeMillis();
	
	public int getNumber() {
		return number;
	}

	public long getLastActiveTime() {
		return lastActiveTime;
	}

	public boolean isRunning() {
		return onRunning.get();
	}
	
	public long getTotalUnHandledMessageCount() {
		return messageQueue.size();
	}
	
	public boolean hasRemindMessage() {
		return !messageQueue.isEmpty();
	}
	
	
	public EventCommittingContextMailBox(int number, int batchSize, IVoidFunction1> handleMessageAction,
			SystemAsyncHelper systemAsyncHelper) {
		Ensure.notNull(systemAsyncHelper, "systemAsyncHelper");
		messageQueue = new ConcurrentLinkedQueue<>();
		aggregateDictDict = new ConcurrentHashMap<>();
		this.batchSize = batchSize;
		this.number = number;
		this.systemAsyncHelper = systemAsyncHelper;
		handler = handleMessageAction;
	}

	public void enqueueMessage(EventCommittingContext message) {
		DomainEventStream eventStream = message.getEventStream();
		Map eventDict = MapUtilx.getOrAdd(aggregateDictDict, eventStream.getAggregateRootId(), () -> new ConcurrentHashMap<>());
		// 添加成功,则...
		if(null == eventDict.putIfAbsent(eventStream.getId(), (byte )1)) {
			message.setMailBox(this);
			messageQueue.offer(message);
			logger.debug(
					"{} enqueued new message. [mailboxNumber: {}, message: {}]",
					this.getClass().getSimpleName(),
					number,
					eventStream);
			lastActiveTime = System.currentTimeMillis();
			tryRun();
		} else {
			throw new DuplicateEventStreamException(eventStream);
		}
	}

	/**
	 * 尝试把mailbox置为使能状态,若成功则执行处理方法
	 */
	public void tryRun() {
		if(onRunning.compareAndSet(false, true)) {
			logger.debug("{} start run. [mailboxNumber: {}]",
					this.getClass().getSimpleName(),
					number);
			systemAsyncHelper.submit(this::processMessages, false);
		}
	}

	/**
	 * 请求完成MailBox的单次运行,如果MailBox中还有剩余消息,则继续尝试运行下一次
	 */
	public void finishRun() {
		lastActiveTime = System.currentTimeMillis();
		logger.debug("{} complete run. [mailboxNumber: {}]",
				this.getClass().getSimpleName(), number);
		onRunning.compareAndSet(true, false);
		if (hasRemindMessage()) {
			tryRun();
		}
	}

	public void removeAggregateAllEventCommittingContexts(String aggregateRootId) {
		aggregateDictDict.remove(aggregateRootId);
	}

	/**
	 * 单位:毫秒
	 */
	public boolean isInactive(long timeoutMilliseconds) {
		return System.currentTimeMillis() - lastActiveTime >= timeoutMilliseconds;
	}

	private Future processMessages() {

		// 这个地方可以不加锁,因为tryRun调用有排他能力
		
			lastActiveTime = System.currentTimeMillis();
			List messageList = new ArrayList<>();
	
			int amount = 0;
			while (amount < batchSize) {
				EventCommittingContext message;
				Map eventDict;
				if (null != (message = messageQueue.poll()) ) {
					if ( null != (eventDict = aggregateDictDict.get(message.getEventStream().getAggregateRootId()))
						&& null != eventDict.remove(message.getEventStream().getId())
						) {
						messageList.add(message);
						amount ++;
					}
				} else {
					break;
				}
			}
			
			// 在列表为空或遇到异常时才在这里执行finishRun()调用
			// 正常情况下的finishRun()调用由handler负责
			if(!messageList.isEmpty()) {
				try {
					handler.trigger(messageList);
				} catch (RuntimeException ex) {
					logger.error("{} run has unknown exception!!! [mailboxNumber: {}]",
							this.getClass().getSimpleName(), number, ex);
					DiscardWrapper.sleepInterruptable(1l);
					finishRun();
				}
			} else {
				finishRun();
			}
		return EJokerFutureUtil.completeFuture();
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy