@Override public void run() { Message msg = decode(envelope.msg.getProtocol(), payload, Message.class); msg.getTrace().setLevel(envelope.msg.getTrace().getLevel()); msg.setRoute(envelope.msg.getRoute()).getRoute().removeHop(0); msg.setRetryEnabled(envelope.msg.getRetryEnabled()); msg.setRetry(envelope.msg.getRetry()); msg.setTimeRemaining(envelope.msg.getTimeRemainingNow()); msg.pushHandler(new ReplyHandler() { @Override public void handleReply(Reply reply) { new ReplyEnvelope(LocalNetwork.this, envelope, reply).send(); } }); owner.deliverMessage(msg, LocalServiceAddress.class.cast(envelope.recipient.getServiceAddress()) .getSessionName()); } });
@Override public ContentChannel handleRequest(final Request request, final ResponseHandler handler) { if (!(request instanceof MbusRequest)) { throw new RequestDeniedException(request); } final Message msg = ((MbusRequest)request).getMessage(); msg.getTrace().trace(6, "Request received by MbusClient."); msg.pushHandler(null); // save user context final Long timeout = request.timeRemaining(TimeUnit.MILLISECONDS); if (timeout != null) { msg.setTimeReceivedNow(); msg.setTimeRemaining(Math.max(1, timeout)); // negative or zero timeout has semantics } msg.setContext(handler); msg.pushHandler(this); queue.add((MbusRequest)request); return null; }
@Override public boolean isProcessable() { Message msg = requestMsg; switch (msg.getType()) { case DocumentProtocol.MESSAGE_PUTDOCUMENT: case DocumentProtocol.MESSAGE_UPDATEDOCUMENT: case DocumentProtocol.MESSAGE_REMOVEDOCUMENT: return true; } return false; }
private Message updateTiming(Message msg) { msg.setTimeReceivedNow(); if (msg.getTimeRemaining() <= 0) { msg.setTimeRemaining((long)(timeout) * 1000L); } return msg; }
@Override public void processMessage(Message message) { int size = message.getApproxSize(); message.setContext(size); pendingSize += size; }
msg.setRoute(net.getRoute(p.route)); msg.setContext(new ReplyContext(request, p.version)); msg.pushHandler(this); msg.setRetryEnabled(p.retryEnabled); msg.setRetry(p.retry); msg.setTimeReceivedNow(); msg.setTimeRemaining(p.timeRemaining); msg.getTrace().setLevel(p.traceLevel); if (msg.getTrace().shouldTrace(TraceLevel.SEND_RECEIVE)) { msg.getTrace().trace(TraceLevel.SEND_RECEIVE, "Message (type " + msg.getType() + ") received at " + serverIdent + " for session '" + p.session + "'.");
/** * A convenience method for assigning the internal trace level and route string to a message before sending it * through the internal mbus session object. * * @param msg the message to send. * @return the document api result object. */ public Result send(Message msg) { try { long reqId = requestId.incrementAndGet(); msg.setContext(reqId); msg.getTrace().setLevel(traceLevel); String toRoute = (msg.getType() == DocumentProtocol.MESSAGE_GETDOCUMENT ? routeForGet : route); if (toRoute != null) { return toResult(reqId, session.send(msg, toRoute, true)); } else { return toResult(reqId, session.send(msg)); } } catch (Exception e) { return new Result(Result.ResultType.FATAL_ERROR, new Error(e.getMessage(), e)); } }
/** * Filter a message against the current sequencing state. If this method returns true, the message has been cleared * for sending and its sequencing information has been added to the state. If this method returns false, it has been * queued for later sending due to sequencing restrictions. This method also sets the sequence id as message * context. * * @param msg The message to filter. * @return True if the message was consumed. */ private boolean filter(Message msg) { long seqId = msg.getSequenceId(); msg.setContext(seqId); synchronized (this) { if (seqMap.containsKey(seqId)) { Queue<Message> queue = seqMap.get(seqId); if (queue == null) { queue = new LinkedList<Message>(); seqMap.put(seqId, queue); } if (msg.getTrace().shouldTrace(TraceLevel.COMPONENT)) { msg.getTrace().trace(TraceLevel.COMPONENT, "Sequencer queued message with sequence id '" + seqId + "'."); } queue.add(msg); return false; } seqMap.put(seqId, null); } return true; }
/** * Internal method for forwarding a sequenced message to the underlying sender. * * @param msg The message to forward. */ private void sequencedSend(Message msg) { if (msg.getTrace().shouldTrace(TraceLevel.COMPONENT)) { msg.getTrace().trace(TraceLevel.COMPONENT, "Sequencer sending message with sequence id '" + msg.getContext() + "'."); } msg.pushHandler(this); sender.handleMessage(msg); }
private OperationStatus createOperationStatus(String id, String message, ErrorCode code, boolean isConditionNotMet, Message msg) { String traceMessage = msg != null && msg.getTrace() != null && msg.getTrace().getLevel() > 0 ? msg.getTrace().toString() : ""; return new OperationStatus(message, id, code, isConditionNotMet, traceMessage); }
private Reply syncSend(Message msg, Duration timeout) { if (timeout != null) { msg.setTimeRemaining(timeout.toMillis()); } try { RequestMonitor monitor = new RequestMonitor(); msg.setContext(monitor); msg.pushHandler(this); // store monitor Result result = null; while (result == null || result.type() == Result.ResultType.TRANSIENT_ERROR) { result = session.send(msg); if (result != null && result.isSuccess()) { break; } Thread.sleep(100); } if (!result.isSuccess()) { throw new DocumentAccessException(result.getError().toString()); } return monitor.waitForReply(); } catch (InterruptedException e) { throw new DocumentAccessException(e); } }
private Result sendInternal(Message message) { synchronized (lock) { if (closed) { return new Result(ErrorCode.SEND_QUEUE_CLOSED, "Source session is closed."); } if (throttlePolicy != null && ! throttlePolicy.canSend(message, pendingCount)) { return new Result(ErrorCode.SEND_QUEUE_FULL, "Too much pending data (" + pendingCount + " messages)."); } message.pushHandler(replyHandler); if (throttlePolicy != null) { throttlePolicy.processMessage(message); } ++pendingCount; } if (message.getTrace().shouldTrace(TraceLevel.COMPONENT)) { message.getTrace().trace(TraceLevel.COMPONENT, "Source session accepted a " + message.getApproxSize() + " byte message. " + pendingCount + " message(s) now pending."); } message.pushHandler(this); sequencer.handleMessage(message); return Result.ACCEPTED; }
public Request newClientRequest(Message msg) { msg.setRoute(Route.parse(server.connectionSpec())); if (msg.getTrace().getLevel() == 0) { msg.getTrace().setLevel(9); } final Request parent = newServerRequest(); try (final ResourceReference ref = References.fromResource(parent)) { return new MbusRequest(parent, URI.create("mbus://remotehost/"), msg); } }
/** * <p>This method handles choking input data so that message bus does not * blindly accept everything. This prevents an application running * out-of-memory in case it fail to choke input data itself. If this method * returns false, it means that it should be rejected.</p> * * @param msg The message to count. * @return True if the message was accepted. */ private boolean checkPending(Message msg) { boolean busy = false; int size = msg.getApproxSize(); if (doAccounting()) { synchronized (this) { busy = ((maxPendingCount > 0 && pendingCount >= maxPendingCount) || (maxPendingSize > 0 && pendingSize >= maxPendingSize)); if (!busy) { pendingCount++; pendingSize += size; } } } if (busy) { return false; } msg.setContext(size); msg.pushHandler(this); return true; }
public DocumentMessage fromDocumentOperation(Processing processing, DocumentOperation documentOperation) { DocumentMessage msg = newMessage(documentOperation); msg.setLoadType(loadType); msg.setPriority(priority); msg.setRoute(requestMsg.getRoute()); msg.setTimeReceivedNow(); msg.setTimeRemaining(requestMsg.getTimeRemainingNow()); msg.getTrace().setLevel(requestMsg.getTrace().getLevel()); if (log.isLoggable(LogLevel.DEBUG)) { log.log(LogLevel.DEBUG, "Created '" + msg.getClass().getName() + "', route = '" + msg.getRoute() + "', priority = '" + msg.getPriority().name() + "', load type = '" + msg.getLoadType() + "', trace level = '" + msg.getTrace().getLevel() + "', time remaining = '" + msg.getTimeRemaining() + "'."); } return msg; }
private void setMessageParameters(DocumentOperationMessageV3 msg, FeederSettings settings) { msg.getMessage().setContext(new ReplyContext(msg.getOperationId(), feedReplies, DocumentOperationType.fromMessage(msg.getMessage()))); if (settings.traceLevel != null) { msg.getMessage().getTrace().setLevel(settings.traceLevel); } if (settings.priority != null) { try { DocumentProtocol.Priority priority = DocumentProtocol.Priority.valueOf(settings.priority); if (msg.getMessage() instanceof DocumentMessage) { ((DocumentMessage) msg.getMessage()).setPriority(priority); } } catch (IllegalArgumentException i) { log.severe(i.getMessage()); } } }
public void handleReply(Reply reply) { if (reply == null) { msg.discard(); } else { Trace trace = msg.getTrace(); if (logTrace) { if (reply.hasErrors()) { reply.setMessage(msg); if (msg.getRoute() != null) { RouteMetricSet metrics = mbus.getMetrics().getRouteMetrics(msg.getRoute()); for (int i = 0; i < reply.getNumErrors(); i++) { metrics.addFailure(reply.getError(i)); metrics.latency.addValue(msg.getTimeReceived() - sendTime);
/** * Constructs a new instance of this class. This is the root node constructor, and will be used by the different * sessions for sending messages. Note that the {@link #discard()} functionality of this class is implemented so * that it passes a null reply to the handler to notify the discard. * * @param mbus The message bus on which we are running. * @param net The network layer we are to transmit through. * @param resender The resender to schedule with. * @param handler The handler to receive the final reply. * @param msg The message being sent. */ public RoutingNode(MessageBus mbus, Network net, Resender resender, ReplyHandler handler, Message msg) { this.mbus = mbus; this.net = net; this.resender = resender; this.handler = handler; this.msg = msg; this.trace = new Trace(msg.getTrace().getLevel()); this.route = msg.getRoute(); this.parent = null; if (route != null) { routeMetrics = mbus.getMetrics().getRouteMetrics(route); } }
@Override public ContentChannel handleRequest(final Request request, final ResponseHandler handler) { if (!(request instanceof MbusRequest)) { throw new UnsupportedOperationException("Expected MbusRequest, got " + request.getClass().getName() + "."); } final Message msg = ((MbusRequest)request).getMessage(); msg.pushHandler(new RespondingReplyHandler(handler)); handleMessage(msg); return null; }
/** * Schedules the given node for resending, if enabled. This will invoke {@link com.yahoo.messagebus.routing.RoutingNode#prepareForRetry()} * if the node was queued. This method is NOT thread-safe, and should only be called by the messenger thread. * * @param node The node to resend. * @return True if the node was queued. */ public boolean scheduleRetry(RoutingNode node) { Message msg = node.getMessage(); if (!msg.getRetryEnabled()) { return false; } int retry = msg.getRetry() + 1; double delay = node.getReply().getRetryDelay(); if (delay < 0) { delay = retryPolicy.getRetryDelay(retry); } if (msg.getTimeRemainingNow() * 0.001 - delay <= 0) { node.addError(ErrorCode.TIMEOUT, "Timeout exceeded by resender, giving up."); return false; } node.prepareForRetry(); // consumes the reply node.getTrace().trace(TraceLevel.COMPONENT, "Message scheduled for retry " + retry + " in " + delay + " seconds."); msg.setRetry(retry); queue.add(new Entry(node, SystemTimer.INSTANCE.milliTime() + (long)(delay * 1000))); return true; }