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

com.taobao.api.internal.tmc.TmcHandler Maven / Gradle / Ivy

The newest version!
package com.taobao.api.internal.tmc;

import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.RejectedExecutionException;

import com.taobao.api.Constants;
import com.taobao.api.internal.toplink.LinkException;
import com.taobao.api.internal.toplink.endpoint.EndpointBaseContext;
import com.taobao.api.internal.toplink.endpoint.EndpointContext;
import com.taobao.api.internal.toplink.util.GZIPHelper;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * 消息服务-内部处理器
 */
class TmcHandler implements com.taobao.api.internal.toplink.endpoint.MessageHandler {

	private static final Log log = LogFactory.getLog("tmcClient");

	protected TmcClient tmcClient;
	protected volatile boolean stopped;

	public TmcHandler(TmcClient tmcClient) {
		this.tmcClient = tmcClient;
	}

	public final void onAckMessage(EndpointBaseContext context) {
	}

	public void onMessage(final EndpointContext context) throws Exception {
		final Map rawMsg = context.getMessage();

		handleMessage(parse(rawMsg), false);
	}

	public void close() {
		this.stopped = true;
	}
	
	public void handleConfirm(Message message){
	    handleConfirm((Long)message.getRaw().get(MessageFields.OUTGOING_ID));
	}
	
	public void handleConfirm(Long outGoingId){
        if(tmcClient.getConfirmThreadPool() != null){
            tmcClient.getConfirmThreadPool().submit(new ConfirmWorker(0, outGoingId) {
                public void run() {
                    try {
                        confirm(this.getOutGoingId());
                    } catch (LinkException e) {
                        //only if connection is closed
                        log.warn(String.format("confirm message fail: %d", this.getOutGoingId()), e);
                        //when it happended, should hold the thread because all message can't confirm success
                        holdTheThread();
                        //retry
                        if(this.getRetry() < 3){
                            this.incrRetry();
                            tmcClient.getConfirmThreadPool().submit(this);
                        }else{
                            log.warn(String.format("confirm message fail 3 times,discard it : %d", this.getOutGoingId()));
                        }
                    }
                }
            });
        }
    }
	
	
	private void holdTheThread(){
		try {
			Thread.sleep(5000);
		} catch (InterruptedException e) {
		}
	}
	
	public void retryMessage(final Message message) throws RejectedExecutionException {
		tmcClient.getThreadPool().submit(new Runnable() {
			public void run() {
				MessageStatus status = new MessageStatus();
				
				try {
					tmcClient.getMessageHandler().onMessage(message, status);
				} catch (Exception e) {
					log.error(String.format("handle message fail: %s", message.getRaw()), e);
					String errorMsg = e.getMessage();
					//错误信息上传128个字节到服务端,用于记录错误信息
					status.fail(errorMsg.substring(0,errorMsg.length() > 128 ? 128 : errorMsg.length()));
				}
				//if enable manual confirm
				if(!tmcClient.isUseDefaultConfirm()){
					return;
				}
				
				if (!status.isFail()) {
					try {
						confirm(message.getId());
					} catch (Exception e) {
						log.warn(String.format("confirm message fail: %s", message.getRaw()), e);
					}
				}else{
					//上传错误信息
				}
			}
		});
	}

	public void handleMessage(final Message message, final boolean ignore) {
		
		log.info(String.format("receive message topic:%s, dataid: %s", message.getTopic(), message.getDataId()));

		while (!stopped) {
			try {
				
				tmcClient.getThreadPool().submit(new Runnable() {
					public void run() {
						MessageStatus status = new MessageStatus();
						long begin = System.currentTimeMillis();
						
						if (!ignore) {
							try {
								tmcClient.getMessageHandler().onMessage(message, status);
							} catch (Exception e) {
								log.error(String.format("handle message fail topic:%s, dataid: %s", message.getTopic(), message.getDataId()), e);
								String errorMsg = e.getMessage();
								//错误信息上传128个字节到服务端,用于记录错误信息
								status.fail(errorMsg.substring(0,errorMsg.length() > 128 ? 128 : errorMsg.length()));
							}
						}
						
						//if enable manual confirm
						if(!tmcClient.isUseDefaultConfirm()){
							status.fail();
						}
						
						try {
							if (ignore || !status.isFail()) {
									
									long end = System.currentTimeMillis();
	
									confirm(message.getId());
									
									log.info(String.format("handle message success topic:%s, dataid: %s. total spent %s ,local spent %s", 
											message.getTopic(), message.getDataId(),
											message.getOutgoingTime() == null ? 0 : end - message.getOutgoingTime().getTime(),
													end - begin));
									
							}
						
							if(status.isFail()){
								fail(message.getId(), status.getReason());
							}
						} catch (Exception e) {
							log.warn(String.format("confirm message fail: %s", message.getRaw()), e);
						}
					}
				});
				
				break;
			} catch (RejectedExecutionException ree) {
				log.warn(String.format("all tmc worker threads are currently busy, waiting 50 ms, appkey:%s-group:%s", tmcClient.getAppKey(), tmcClient.getGroupName()));
				try {
					Thread.sleep(50L);
				} catch (InterruptedException ie) {
					Thread.currentThread().interrupt();
				}
			}
		}
	}

	protected void confirm(Map message) throws LinkException {
	    confirm((Long)message.get(MessageFields.OUTGOING_ID));
	}
	
	protected void confirm(Long outGoingId) throws LinkException {
	    Map msg = new HashMap();
        msg.put(MessageFields.KIND, MessageKind.Confirm);
        msg.put(MessageFields.CONFIRM_ID, outGoingId);
        tmcClient.getClient().send(msg);
	}
	
	protected void fail(Long outGoingId,String errorMsg) throws LinkException {
	    Map msg = new HashMap();
        msg.put(MessageFields.KIND, MessageKind.Failed);
        msg.put(MessageFields.CONFIRM_ID, outGoingId);
        msg.put(MessageFields.MSG, errorMsg);
        tmcClient.getClient().send(msg);
	}

	protected Message parse(Map raw) throws IOException {
		Message msg = new Message();
		msg.setRaw(raw);
		msg.setId((Long) raw.get(MessageFields.OUTGOING_ID));
		msg.setTopic((String) raw.get(MessageFields.DATA_TOPIC));
		msg.setPubAppKey((String) raw.get(MessageFields.DATA_OUTGOING_PUBLISHER));
		msg.setUserId((Long) raw.get(MessageFields.DATA_OUTGOING_USER_ID));
		msg.setUserNick((String) raw.get(MessageFields.DATA_OUTGOING_USER_NICK));
		msg.setPubTime((Date) raw.get(MessageFields.DATA_PUBLISH_TIME));
		
		Object dataId = raw.get(MessageFields.DATA_DATAID);
		if(dataId != null){
			msg.setDataId(dataId.toString());
		}
		
		Object time = raw.get(MessageFields.DATA_ATTACH_OUTGOING_TIME);
		if (time != null){
			msg.setOutgoingTime((Date) time);
		}

		Object content = raw.get(MessageFields.DATA_CONTENT);
		if (content instanceof String){
			msg.setContent((String) content);
		} else if (content instanceof byte[]) {
			msg.setContent(new String(GZIPHelper.unzip((byte[]) content), Constants.CHARSET_UTF8));
		}
		return msg;
	}

	public abstract class ConfirmWorker implements Runnable{
		
		private int retry;
		private final Long outGoingId;

		public ConfirmWorker(int retry,Long outGoingId){
			this.retry = retry;
			this.outGoingId = outGoingId;
		}

		public void incrRetry() {
			this.retry = this.retry + 1;
		}

		public int getRetry() {
			return retry;
		}

        public Long getOutGoingId() {
            return outGoingId;
        }
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy