Search in sources :

Example 66 with Message

use of org.apache.helix.model.Message in project helix by apache.

the class HelixTaskExecutor method onMessage.

@Override
@PreFetch(enabled = false)
public void onMessage(String instanceName, List<Message> messages, NotificationContext changeContext) {
    HelixManager manager = changeContext.getManager();
    // TODO: see if we should have a separate notification call for resetting
    if (changeContext.getType() == Type.FINALIZE) {
        reset();
        return;
    }
    if (changeContext.getType() == Type.INIT) {
        init();
    // continue to process messages
    }
    // if prefetch is disabled in MessageListenerCallback, we need to read all new messages from zk.
    if (messages == null || messages.isEmpty()) {
        // If no messages are given, check and read all new messages.
        messages = readNewMessagesFromZK(manager, instanceName, changeContext.getChangeType());
    }
    if (_isShuttingDown) {
        StringBuilder sb = new StringBuilder();
        for (Message message : messages) {
            sb.append(message.getMsgId() + ",");
        }
        LOG.info("Helix task executor is shutting down, discard unprocessed messages : " + sb.toString());
        return;
    }
    // Update message count
    if (_messageQueueMonitor != null) {
        _messageQueueMonitor.setMessageQueueBacklog(messages.size());
    }
    if (messages.isEmpty()) {
        LOG.info("No Messages to process");
        return;
    }
    // sort message by creation timestamp, so message created earlier is processed first
    Collections.sort(messages, Message.CREATE_TIME_COMPARATOR);
    HelixDataAccessor accessor = manager.getHelixDataAccessor();
    Builder keyBuilder = accessor.keyBuilder();
    // message handlers created
    Map<String, MessageHandler> stateTransitionHandlers = new HashMap<>();
    List<MessageHandler> nonStateTransitionHandlers = new ArrayList<>();
    // message read
    List<Message> readMsgs = new ArrayList<>();
    String sessionId = manager.getSessionId();
    List<String> curResourceNames = accessor.getChildNames(keyBuilder.currentStates(instanceName, sessionId));
    List<PropertyKey> createCurStateKeys = new ArrayList<>();
    List<CurrentState> metaCurStates = new ArrayList<>();
    Set<String> createCurStateNames = new HashSet<>();
    for (Message message : messages) {
        // situations such as register a new message handler factory
        if (message.getMsgType().equalsIgnoreCase(MessageType.NO_OP.toString())) {
            LOG.info("Dropping NO-OP message. mid: " + message.getId() + ", from: " + message.getMsgSrc());
            reportAndRemoveMessage(message, accessor, instanceName, ProcessedMessageState.DISCARDED);
            continue;
        }
        if (message.isExpired()) {
            LOG.info("Dropping expired message. mid: " + message.getId() + ", from: " + message.getMsgSrc() + " relayed from: " + message.getRelaySrcHost());
            reportAndRemoveMessage(message, accessor, instanceName, ProcessedMessageState.DISCARDED);
            continue;
        }
        String tgtSessionId = message.getTgtSessionId();
        // sessionId mismatch normally means message comes from expired session, just remove it
        if (!sessionId.equals(tgtSessionId) && !tgtSessionId.equals("*")) {
            String warningMessage = "SessionId does NOT match. expected sessionId: " + sessionId + ", tgtSessionId in message: " + tgtSessionId + ", messageId: " + message.getMsgId();
            LOG.warn(warningMessage);
            reportAndRemoveMessage(message, accessor, instanceName, ProcessedMessageState.DISCARDED);
            _statusUpdateUtil.logWarning(message, HelixStateMachineEngine.class, warningMessage, manager);
            // upon session mismatch after a new session is established
            if (manager.getInstanceType() == InstanceType.PARTICIPANT || manager.getInstanceType() == InstanceType.CONTROLLER_PARTICIPANT) {
                if (message.getCreateTimeStamp() > manager.getSessionStartTime()) {
                    syncSessionToController(manager);
                }
            }
            continue;
        }
        if ((manager.getInstanceType() == InstanceType.CONTROLLER || manager.getInstanceType() == InstanceType.CONTROLLER_PARTICIPANT) && MessageType.PARTICIPANT_SESSION_CHANGE.name().equals(message.getMsgType())) {
            LOG.info(String.format("Controller received PARTICIPANT_SESSION_CHANGE msg from src: %s", message.getMsgSrc()));
            PropertyKey key = new Builder(manager.getClusterName()).liveInstances();
            List<LiveInstance> liveInstances = manager.getHelixDataAccessor().getChildValues(key);
            _controller.onLiveInstanceChange(liveInstances, changeContext);
            reportAndRemoveMessage(message, accessor, instanceName, ProcessedMessageState.COMPLETED);
            continue;
        }
        // don't process message that is of READ or UNPROCESSABLE state
        if (MessageState.NEW != message.getMsgState()) {
            // check for the status and ignore if its already read
            if (LOG.isTraceEnabled()) {
                LOG.trace("Message already read. msgId: " + message.getMsgId());
            }
            continue;
        }
        // State Transition Cancellation
        if (message.getMsgType().equals(MessageType.STATE_TRANSITION_CANCELLATION.name())) {
            boolean success = cancelNotStartedStateTransition(message, stateTransitionHandlers, accessor, instanceName);
            if (success) {
                continue;
            }
        }
        _monitor.reportReceivedMessage(message);
        // create message handlers, if handlers not found, leave its state as NEW
        try {
            MessageHandler createHandler = createMessageHandler(message, changeContext);
            if (createHandler == null) {
                continue;
            }
            if (message.getMsgType().equals(MessageType.STATE_TRANSITION.name()) || message.getMsgType().equals(MessageType.STATE_TRANSITION_CANCELLATION.name())) {
                stateTransitionHandlers.put(getMessageTarget(message.getResourceName(), message.getPartitionName()), createHandler);
            } else {
                nonStateTransitionHandlers.add(createHandler);
            }
        } catch (Exception e) {
            LOG.error("Failed to create message handler for " + message.getMsgId(), e);
            String error = "Failed to create message handler for " + message.getMsgId() + ", exception: " + e;
            _statusUpdateUtil.logError(message, HelixStateMachineEngine.class, e, error, manager);
            message.setMsgState(MessageState.UNPROCESSABLE);
            removeMessageFromZK(accessor, message, instanceName);
            LOG.error("Message cannot be processed: " + message.getRecord(), e);
            _monitor.reportProcessedMessage(message, ParticipantMessageMonitor.ProcessedMessageState.DISCARDED);
            continue;
        }
        markReadMessage(message, changeContext, manager);
        readMsgs.add(message);
        // do it for non-controller and state transition messages only
        if (!message.isControlerMsg() && message.getMsgType().equals(Message.MessageType.STATE_TRANSITION.name())) {
            String resourceName = message.getResourceName();
            if (!curResourceNames.contains(resourceName) && !createCurStateNames.contains(resourceName)) {
                createCurStateNames.add(resourceName);
                createCurStateKeys.add(keyBuilder.currentState(instanceName, sessionId, resourceName));
                CurrentState metaCurState = new CurrentState(resourceName);
                metaCurState.setBucketSize(message.getBucketSize());
                metaCurState.setStateModelDefRef(message.getStateModelDef());
                metaCurState.setSessionId(sessionId);
                metaCurState.setBatchMessageMode(message.getBatchMessageMode());
                String ftyName = message.getStateModelFactoryName();
                if (ftyName != null) {
                    metaCurState.setStateModelFactoryName(ftyName);
                } else {
                    metaCurState.setStateModelFactoryName(HelixConstants.DEFAULT_STATE_MODEL_FACTORY);
                }
                metaCurStates.add(metaCurState);
            }
        }
    }
    // batch create curState meta
    if (createCurStateKeys.size() > 0) {
        try {
            accessor.createChildren(createCurStateKeys, metaCurStates);
        } catch (Exception e) {
            LOG.error("fail to create cur-state znodes for messages: " + readMsgs, e);
        }
    }
    // update message state to READ in batch and schedule all read messages
    if (readMsgs.size() > 0) {
        updateMessageState(readMsgs, accessor, instanceName);
        for (MessageHandler handler : stateTransitionHandlers.values()) {
            HelixTask task = new HelixTask(handler._message, changeContext, handler, this);
            scheduleTask(task);
        }
        for (MessageHandler handler : nonStateTransitionHandlers) {
            HelixTask task = new HelixTask(handler._message, changeContext, handler, this);
            scheduleTask(task);
        }
    }
}
Also used : HelixStateMachineEngine(org.apache.helix.participant.HelixStateMachineEngine) Message(org.apache.helix.model.Message) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) HashMap(java.util.HashMap) HelixConfigScopeBuilder(org.apache.helix.model.builder.HelixConfigScopeBuilder) Builder(org.apache.helix.PropertyKey.Builder) ArrayList(java.util.ArrayList) LiveInstance(org.apache.helix.model.LiveInstance) CurrentState(org.apache.helix.model.CurrentState) HashSet(java.util.HashSet) HelixManager(org.apache.helix.HelixManager) HelixException(org.apache.helix.HelixException) HelixDataAccessor(org.apache.helix.HelixDataAccessor) PropertyKey(org.apache.helix.PropertyKey) PreFetch(org.apache.helix.api.listeners.PreFetch)

Example 67 with Message

use of org.apache.helix.model.Message in project helix by apache.

the class HelixTaskExecutor method scheduleTask.

@Override
public boolean scheduleTask(MessageTask task) {
    String taskId = task.getTaskId();
    Message message = task.getMessage();
    NotificationContext notificationContext = task.getNotificationContext();
    HelixManager manager = notificationContext.getManager();
    try {
        // Check to see if dedicate thread pool for handling state transition messages is configured or provided.
        updateStateTransitionMessageThreadPool(message, manager);
        LOG.info("Scheduling message: " + taskId);
        // System.out.println("sched msg: " + message.getPartitionName() + "-"
        // + message.getTgtName() + "-" + message.getFromState() + "-"
        // + message.getToState());
        _statusUpdateUtil.logInfo(message, HelixTaskExecutor.class, "Message handling task scheduled", manager);
        // sync'ed
        synchronized (_lock) {
            if (!_taskMap.containsKey(taskId)) {
                ExecutorService exeSvc = findExecutorServiceForMsg(message);
                if (exeSvc == null) {
                    LOG.warn(String.format("Threadpool is null for type %s of message %s", message.getMsgType(), message.getMsgId()));
                    return false;
                }
                LOG.info("Submit task: " + taskId + " to pool: " + exeSvc);
                Future<HelixTaskResult> future = exeSvc.submit(task);
                _messageTaskMap.putIfAbsent(getMessageTarget(message.getResourceName(), message.getPartitionName()), taskId);
                TimerTask timerTask = null;
                if (message.getExecutionTimeout() > 0) {
                    timerTask = new MessageTimeoutTask(this, task);
                    _timer.schedule(timerTask, message.getExecutionTimeout());
                    LOG.info("Message starts with timeout " + message.getExecutionTimeout() + " MsgId: " + task.getTaskId());
                } else {
                    LOG.debug("Message does not have timeout. MsgId: " + task.getTaskId());
                }
                _taskMap.put(taskId, new MessageTaskInfo(task, future, timerTask));
                LOG.info("Message: " + taskId + " handling task scheduled");
                return true;
            } else {
                _statusUpdateUtil.logWarning(message, HelixTaskExecutor.class, "Message handling task already sheduled for " + taskId, manager);
            }
        }
    } catch (Exception e) {
        LOG.error("Error while executing task. " + message, e);
        _statusUpdateUtil.logError(message, HelixTaskExecutor.class, e, "Error while executing task " + e, manager);
    }
    return false;
}
Also used : NotificationContext(org.apache.helix.NotificationContext) HelixManager(org.apache.helix.HelixManager) Message(org.apache.helix.model.Message) TimerTask(java.util.TimerTask) ExecutorService(java.util.concurrent.ExecutorService) HelixException(org.apache.helix.HelixException)

Example 68 with Message

use of org.apache.helix.model.Message in project helix by apache.

the class HelixTaskExecutor method readNewMessagesFromZK.

private List<Message> readNewMessagesFromZK(HelixManager manager, String instanceName, HelixConstants.ChangeType changeType) {
    HelixDataAccessor accessor = manager.getHelixDataAccessor();
    Builder keyBuilder = accessor.keyBuilder();
    Set<String> messageIds = new HashSet<>();
    if (changeType.equals(HelixConstants.ChangeType.MESSAGE)) {
        messageIds.addAll(accessor.getChildNames(keyBuilder.messages(instanceName)));
    } else if (changeType.equals(HelixConstants.ChangeType.MESSAGES_CONTROLLER)) {
        messageIds.addAll(accessor.getChildNames(keyBuilder.controllerMessages()));
    } else {
        LOG.warn("Unexpected ChangeType for Message Change CallbackHandler: " + changeType);
        return Collections.emptyList();
    }
    // In case the cache contains any deleted message Id, clean up
    _knownMessageIds.retainAll(messageIds);
    messageIds.removeAll(_knownMessageIds);
    List<PropertyKey> keys = new ArrayList<>();
    for (String messageId : messageIds) {
        if (changeType.equals(HelixConstants.ChangeType.MESSAGE)) {
            keys.add(keyBuilder.message(instanceName, messageId));
        } else if (changeType.equals(HelixConstants.ChangeType.MESSAGES_CONTROLLER)) {
            keys.add(keyBuilder.controllerMessage(messageId));
        }
    }
    List<Message> newMessages = accessor.getProperty(keys);
    // Message may be removed before get read, clean up null messages.
    Iterator<Message> messageIterator = newMessages.iterator();
    while (messageIterator.hasNext()) {
        if (messageIterator.next() == null) {
            messageIterator.remove();
        }
    }
    return newMessages;
}
Also used : HelixDataAccessor(org.apache.helix.HelixDataAccessor) Message(org.apache.helix.model.Message) HelixConfigScopeBuilder(org.apache.helix.model.builder.HelixConfigScopeBuilder) Builder(org.apache.helix.PropertyKey.Builder) ArrayList(java.util.ArrayList) PropertyKey(org.apache.helix.PropertyKey) HashSet(java.util.HashSet)

Example 69 with Message

use of org.apache.helix.model.Message in project helix by apache.

the class DefaultMessagingService method send.

@Override
public int send(final Criteria recipientCriteria, final Message message, AsyncCallback callbackOnReply, int timeOut, int retryCount) {
    Map<InstanceType, List<Message>> generateMessage = generateMessage(recipientCriteria, message);
    int totalMessageCount = 0;
    for (List<Message> messages : generateMessage.values()) {
        totalMessageCount += messages.size();
    }
    _logger.info("Send " + totalMessageCount + " messages with criteria " + recipientCriteria);
    if (totalMessageCount == 0) {
        return 0;
    }
    String correlationId = null;
    if (callbackOnReply != null) {
        int totalTimeout = timeOut * (retryCount + 1);
        if (totalTimeout < 0) {
            totalTimeout = -1;
        }
        callbackOnReply.setTimeout(totalTimeout);
        correlationId = UUID.randomUUID().toString();
        for (List<Message> messages : generateMessage.values()) {
            callbackOnReply.setMessagesSent(messages);
        }
        _asyncCallbackService.registerAsyncCallback(correlationId, callbackOnReply);
    }
    for (InstanceType receiverType : generateMessage.keySet()) {
        List<Message> list = generateMessage.get(receiverType);
        for (Message tempMessage : list) {
            tempMessage.setRetryCount(retryCount);
            tempMessage.setExecutionTimeout(timeOut);
            tempMessage.setSrcInstanceType(_manager.getInstanceType());
            if (correlationId != null) {
                tempMessage.setCorrelationId(correlationId);
            }
            HelixDataAccessor accessor = _manager.getHelixDataAccessor();
            Builder keyBuilder = accessor.keyBuilder();
            if (receiverType == InstanceType.CONTROLLER) {
                // _manager.getDataAccessor().setProperty(PropertyType.MESSAGES_CONTROLLER,
                // tempMessage,
                // tempMessage.getId());
                accessor.setProperty(keyBuilder.controllerMessage(tempMessage.getId()), tempMessage);
            }
            if (receiverType == InstanceType.PARTICIPANT) {
                accessor.setProperty(keyBuilder.message(tempMessage.getTgtName(), tempMessage.getId()), tempMessage);
            }
        }
    }
    if (callbackOnReply != null) {
        // start timer if timeout is set
        callbackOnReply.startTimer();
    }
    return totalMessageCount;
}
Also used : HelixDataAccessor(org.apache.helix.HelixDataAccessor) Message(org.apache.helix.model.Message) ConfigScopeBuilder(org.apache.helix.model.builder.ConfigScopeBuilder) Builder(org.apache.helix.PropertyKey.Builder) ArrayList(java.util.ArrayList) List(java.util.List) InstanceType(org.apache.helix.InstanceType)

Example 70 with Message

use of org.apache.helix.model.Message in project helix by apache.

the class TestSchedulerMessage method testSchedulerMsg.

@Test(dependsOnMethods = "testSchedulerZeroMsg")
public void testSchedulerMsg() throws Exception {
    _factory._results.clear();
    HelixManager manager = null;
    for (int i = 0; i < NODE_NR; i++) {
        _participants[i].getMessagingService().registerMessageHandlerFactory(_factory.getMessageTypes(), _factory);
        // _startCMResultMap.get(hostDest)._manager;
        manager = _participants[i];
    }
    Message schedulerMessage = new Message(MessageType.SCHEDULER_MSG + "", UUID.randomUUID().toString());
    schedulerMessage.setTgtSessionId("*");
    schedulerMessage.setTgtName("CONTROLLER");
    // TODO: change it to "ADMIN" ?
    schedulerMessage.setSrcName("CONTROLLER");
    // schedulerMessage.getRecord().setSimpleField(DefaultSchedulerMessageHandlerFactory.SCHEDULER_TASK_QUEUE,
    // "TestSchedulerMsg");
    // Template for the individual message sent to each participant
    Message msg = new Message(_factory.getMessageTypes().get(0), "Template");
    msg.setTgtSessionId("*");
    msg.setMsgState(MessageState.NEW);
    // Criteria to send individual messages
    Criteria cr = new Criteria();
    cr.setInstanceName("localhost_%");
    cr.setRecipientInstanceType(InstanceType.PARTICIPANT);
    cr.setSessionSpecific(false);
    cr.setResource("%");
    cr.setPartition("%");
    ObjectMapper mapper = new ObjectMapper();
    SerializationConfig serializationConfig = mapper.getSerializationConfig();
    serializationConfig.set(SerializationConfig.Feature.INDENT_OUTPUT, true);
    StringWriter sw = new StringWriter();
    mapper.writeValue(sw, cr);
    String crString = sw.toString();
    schedulerMessage.getRecord().setSimpleField("Criteria", crString);
    schedulerMessage.getRecord().setMapField("MessageTemplate", msg.getRecord().getSimpleFields());
    schedulerMessage.getRecord().setSimpleField("TIMEOUT", "-1");
    HelixDataAccessor helixDataAccessor = manager.getHelixDataAccessor();
    Builder keyBuilder = helixDataAccessor.keyBuilder();
    helixDataAccessor.createControllerMessage(schedulerMessage);
    for (int i = 0; i < 30; i++) {
        Thread.sleep(2000);
        if (_PARTITIONS == _factory._results.size()) {
            break;
        }
    }
    Assert.assertEquals(_PARTITIONS, _factory._results.size());
    PropertyKey controllerTaskStatus = keyBuilder.controllerTaskStatus(MessageType.SCHEDULER_MSG.name(), schedulerMessage.getMsgId());
    int messageResultCount = 0;
    for (int i = 0; i < 10; i++) {
        Thread.sleep(1000);
        ZNRecord statusUpdate = helixDataAccessor.getProperty(controllerTaskStatus).getRecord();
        Assert.assertTrue(statusUpdate.getMapField("SentMessageCount").get("MessageCount").equals("" + (_PARTITIONS * 3)));
        for (String key : statusUpdate.getMapFields().keySet()) {
            if (key.startsWith("MessageResult ")) {
                messageResultCount++;
                Assert.assertTrue(statusUpdate.getMapField(key).size() > 1);
            }
        }
        if (messageResultCount == _PARTITIONS * 3) {
            break;
        } else {
            Thread.sleep(2000);
        }
    }
    Assert.assertEquals(messageResultCount, _PARTITIONS * 3);
    int count = 0;
    for (Set<String> val : _factory._results.values()) {
        count += val.size();
    }
    Assert.assertEquals(count, _PARTITIONS * 3);
    // test the ZkPathDataDumpTask
    String controllerStatusPath = PropertyPathBuilder.controllerStatusUpdate(manager.getClusterName());
    List<String> subPaths = _gZkClient.getChildren(controllerStatusPath);
    Assert.assertTrue(subPaths.size() > 0);
    for (String subPath : subPaths) {
        String nextPath = controllerStatusPath + "/" + subPath;
        List<String> subsubPaths = _gZkClient.getChildren(nextPath);
        Assert.assertTrue(subsubPaths.size() > 0);
    }
    String instanceStatusPath = PropertyPathBuilder.instanceStatusUpdate(manager.getClusterName(), "localhost_" + (START_PORT));
    subPaths = _gZkClient.getChildren(instanceStatusPath);
    Assert.assertTrue(subPaths.size() == 0);
    for (String subPath : subPaths) {
        String nextPath = instanceStatusPath + "/" + subPath;
        List<String> subsubPaths = _gZkClient.getChildren(nextPath);
        Assert.assertTrue(subsubPaths.size() > 0);
        for (String subsubPath : subsubPaths) {
            String nextnextPath = nextPath + "/" + subsubPath;
            Assert.assertTrue(_gZkClient.getChildren(nextnextPath).size() > 0);
        }
    }
    Thread.sleep(3000);
    ZKPathDataDumpTask dumpTask = new ZKPathDataDumpTask(manager, 0L, 0L, Integer.MAX_VALUE);
    dumpTask.run();
    subPaths = _gZkClient.getChildren(controllerStatusPath);
    Assert.assertTrue(subPaths.size() > 0);
    for (String subPath : subPaths) {
        String nextPath = controllerStatusPath + "/" + subPath;
        List<String> subsubPaths = _gZkClient.getChildren(nextPath);
        Assert.assertTrue(subsubPaths.size() == 0);
    }
    subPaths = _gZkClient.getChildren(instanceStatusPath);
    Assert.assertTrue(subPaths.size() == 0);
    for (String subPath : subPaths) {
        String nextPath = instanceStatusPath + "/" + subPath;
        List<String> subsubPaths = _gZkClient.getChildren(nextPath);
        Assert.assertTrue(subsubPaths.size() > 0);
        for (String subsubPath : subsubPaths) {
            String nextnextPath = nextPath + "/" + subsubPath;
            Assert.assertTrue(_gZkClient.getChildren(nextnextPath).size() == 0);
        }
    }
}
Also used : HelixManager(org.apache.helix.HelixManager) Message(org.apache.helix.model.Message) SerializationConfig(org.codehaus.jackson.map.SerializationConfig) Builder(org.apache.helix.PropertyKey.Builder) PropertyPathBuilder(org.apache.helix.PropertyPathBuilder) Criteria(org.apache.helix.Criteria) ZKPathDataDumpTask(org.apache.helix.monitoring.ZKPathDataDumpTask) HelixDataAccessor(org.apache.helix.HelixDataAccessor) StringWriter(java.io.StringWriter) ObjectMapper(org.codehaus.jackson.map.ObjectMapper) PropertyKey(org.apache.helix.PropertyKey) ZNRecord(org.apache.helix.ZNRecord) Test(org.testng.annotations.Test)

Aggregations

Message (org.apache.helix.model.Message)116 Test (org.testng.annotations.Test)53 ArrayList (java.util.ArrayList)36 HelixDataAccessor (org.apache.helix.HelixDataAccessor)30 Builder (org.apache.helix.PropertyKey.Builder)28 HelixManager (org.apache.helix.HelixManager)22 ZNRecord (org.apache.helix.ZNRecord)22 Criteria (org.apache.helix.Criteria)21 Date (java.util.Date)19 HashMap (java.util.HashMap)18 Partition (org.apache.helix.model.Partition)18 PropertyKey (org.apache.helix.PropertyKey)17 LiveInstance (org.apache.helix.model.LiveInstance)13 ZKHelixDataAccessor (org.apache.helix.manager.zk.ZKHelixDataAccessor)12 NotificationContext (org.apache.helix.NotificationContext)11 CurrentState (org.apache.helix.model.CurrentState)10 HelixException (org.apache.helix.HelixException)9 Resource (org.apache.helix.model.Resource)9 StringWriter (java.io.StringWriter)8 List (java.util.List)8