use of io.vertx.proton.ProtonSender in project hono by eclipse.
the class ForwardingDownstreamAdapter method onClientAttach.
@Override
public final void onClientAttach(final UpstreamReceiver client, final Handler<AsyncResult<Void>> resultHandler) {
if (!running) {
throw new IllegalStateException("adapter must be started first");
}
Objects.requireNonNull(client);
Objects.requireNonNull(resultHandler);
ProtonSender sender = activeSenders.get(client);
if (sender != null && sender.isOpen()) {
logger.info("reusing existing downstream sender [con: {}, link: {}]", client.getConnectionId(), client.getLinkId());
resultHandler.handle(Future.succeededFuture());
} else {
removeSender(client);
// register the result handler to be failed if the connection to the downstream container fails during
// the attempt to create a downstream sender
clientAttachHandlers.add(resultHandler);
Future<Void> tracker = Future.future();
tracker.setHandler(attempt -> {
if (attempt.succeeded()) {
logger.info("created downstream sender [con: {}, link: {}]", client.getConnectionId(), client.getLinkId());
} else {
logger.warn("can't create downstream sender [con: {}, link: {}]: {}", client.getConnectionId(), client.getLinkId(), attempt.cause().getMessage());
}
clientAttachHandlers.remove(resultHandler);
resultHandler.handle(attempt);
});
final ResourceIdentifier targetAddress = ResourceIdentifier.fromString(client.getTargetAddress());
createSender(targetAddress, replenishedSender -> handleFlow(replenishedSender, client), closeHook -> {
removeSender(client);
closeReceiver(client);
}).compose(createdSender -> {
addSender(client, createdSender);
tracker.complete();
}, tracker);
}
}
use of io.vertx.proton.ProtonSender in project hono by eclipse.
the class ForwardingDownstreamAdapter method processMessage.
@Override
public final void processMessage(final UpstreamReceiver client, final ProtonDelivery upstreamDelivery, final Message msg) {
if (!running) {
throw new IllegalStateException("adapter must be started first");
}
Objects.requireNonNull(client);
Objects.requireNonNull(msg);
Objects.requireNonNull(upstreamDelivery);
ProtonSender sender = activeSenders.get(client);
if (sender == null) {
logger.info("no downstream sender for link [{}] available, discarding message and closing link with client", client.getLinkId());
client.close(ErrorConditions.ERROR_NO_DOWNSTREAM_CONSUMER);
} else if (sender.isOpen()) {
if (sender.sendQueueFull()) {
if (upstreamDelivery.remotelySettled()) {
// sender has sent the message pre-settled, i.e. we can simply discard the message
logger.debug("no downstream credit available for link [{}], discarding message [{}]", client.getLinkId(), msg.getMessageId());
ProtonHelper.accepted(upstreamDelivery, true);
metrics.incrementDiscardedMessages(sender.getTarget().getAddress());
} else {
// sender needs to be informed that we cannot process the message
logger.debug("no downstream credit available for link [{}], releasing message [{}]", client.getLinkId(), msg.getMessageId());
ProtonHelper.released(upstreamDelivery, true);
metrics.incrementUndeliverableMessages(sender.getTarget().getAddress());
}
} else {
logger.trace("forwarding message [id: {}, to: {}, content-type: {}] to downstream container [{}], credit available: {}, queued: {}", msg.getMessageId(), msg.getAddress(), msg.getContentType(), getDownstreamContainer(), sender.getCredit(), sender.getQueued());
forwardMessage(sender, msg, upstreamDelivery);
metrics.incrementProcessedMessages(sender.getTarget().getAddress());
}
} else {
logger.warn("downstream sender for link [{}] is not open, discarding message and closing link with client", client.getLinkId());
client.close(ErrorConditions.ERROR_NO_DOWNSTREAM_CONSUMER);
onClientDetach(client);
metrics.incrementDiscardedMessages(sender.getTarget().getAddress());
}
}
use of io.vertx.proton.ProtonSender in project hono by eclipse.
the class SenderFactoryImpl method newSender.
Future<ProtonSender> newSender(final ProtonConnection connection, final ProtonSession session, final ResourceIdentifier address, final ProtonQoS qos, final Handler<ProtonSender> sendQueueDrainHandler, final Handler<String> closeHook) {
Future<ProtonSender> result = Future.future();
ProtonSender sender = session.createSender(getTenantOnlyTargetAddress(address));
sender.setQoS(qos);
sender.setAutoSettle(true);
sender.sendQueueDrainHandler(sendQueueDrainHandler);
sender.openHandler(openAttempt -> {
if (openAttempt.succeeded()) {
LOG.debug("sender [{}] for container [{}] open", address, connection.getRemoteContainer());
result.complete(openAttempt.result());
} else {
LOG.debug("could not open sender [{}] for container [{}]", address, connection.getRemoteContainer(), openAttempt.cause());
result.fail(openAttempt.cause());
}
});
sender.closeHandler(closed -> {
if (closed.succeeded()) {
LOG.debug("sender [{}] for container [{}] closed", address, connection.getRemoteContainer());
} else {
LOG.debug("sender [{}] for container [{}] closed: {}", address, connection.getRemoteContainer(), closed.cause().getMessage());
}
sender.close();
if (closeHook != null) {
closeHook.handle(address.getResourceId());
}
});
sender.detachHandler(detached -> {
if (detached.succeeded()) {
LOG.debug("sender [{}] detached (with closed=false) by peer [{}]", address, connection.getRemoteContainer());
} else {
LOG.debug("sender [{}] detached (with closed=false) by peer [{}]: {}", address, connection.getRemoteContainer(), detached.cause().getMessage());
}
sender.close();
if (closeHook != null) {
closeHook.handle(address.getResourceId());
}
});
sender.open();
return result;
}
use of io.vertx.proton.ProtonSender in project hono by eclipse.
the class ForwardingDownstreamAdapterTest method testHandleFlowForwardsDrainRequestUpstream.
/**
* Verifies that <em>drain</em> requests received from the downstream container are forwarded
* to upstream clients.
*/
@SuppressWarnings("unchecked")
@Test
public void testHandleFlowForwardsDrainRequestUpstream() {
final UpstreamReceiver client = newClient();
when(client.getTargetAddress()).thenReturn(targetAddress.toString());
final ProtonSender drainingSender = newMockSender(true);
// GIVEN an adapter with a connection to the downstream container and a client attached
givenADownstreamAdapter();
adapter.setDownstreamConnectionFactory(connectionFactory);
adapter.start(Future.future());
adapter.addSender(client, drainingSender);
// WHEN the downstream sender drains the adapter
adapter.handleFlow(drainingSender, client);
// THEN assert that the upstream client has been drained
verify(client).drain(anyLong(), any(Handler.class));
}
use of io.vertx.proton.ProtonSender in project hono by eclipse.
the class ForwardingDownstreamAdapterTest method testDownstreamDisconnectClosesUpstreamReceivers.
/**
* Verifies that all links to upstream clients are closed when the connection to the
* downstream container is lost.
*/
@Test
public void testDownstreamDisconnectClosesUpstreamReceivers() {
final UpstreamReceiver client = newClient();
final ProtonSender downstreamSender = newMockSender(false);
// expect the connection factory to be invoked twice
// first on initial connection
// second on re-connect attempt
HandlerCapturingConnectionFactory factory = new HandlerCapturingConnectionFactory(con, 2);
// GIVEN an adapter connected to a downstream container
givenADownstreamAdapter(downstreamSender);
adapter.setDownstreamConnectionFactory(factory);
adapter.start(Future.future());
adapter.addSender(client, downstreamSender);
// WHEN the downstream connection fails
factory.getDisconnectHandler().handle(con);
// THEN the adapter tries to reconnect to the downstream container and has closed all upstream receivers
factory.await(1, TimeUnit.SECONDS);
verify(client).close(any(ErrorCondition.class));
assertTrue(adapter.isActiveSendersEmpty());
assertTrue(adapter.isSendersPerConnectionEmpty());
}
Aggregations