Search in sources :

Example 1 with Exceptions

use of org.apache.pulsar.functions.utils.Exceptions in project pulsar by apache.

the class ServerCnx method handleProducer.

@Override
protected void handleProducer(final CommandProducer cmdProducer) {
    checkArgument(state == State.Connected);
    final long producerId = cmdProducer.getProducerId();
    final long requestId = cmdProducer.getRequestId();
    // Use producer name provided by client if present
    final String producerName = cmdProducer.hasProducerName() ? cmdProducer.getProducerName() : service.generateUniqueProducerName();
    final long epoch = cmdProducer.getEpoch();
    final boolean userProvidedProducerName = cmdProducer.isUserProvidedProducerName();
    final boolean isEncrypted = cmdProducer.isEncrypted();
    final Map<String, String> metadata = CommandUtils.metadataFromCommand(cmdProducer);
    final SchemaData schema = cmdProducer.hasSchema() ? getSchema(cmdProducer.getSchema()) : null;
    final ProducerAccessMode producerAccessMode = cmdProducer.getProducerAccessMode();
    final Optional<Long> topicEpoch = cmdProducer.hasTopicEpoch() ? Optional.of(cmdProducer.getTopicEpoch()) : Optional.empty();
    final boolean isTxnEnabled = cmdProducer.isTxnEnabled();
    final String initialSubscriptionName = cmdProducer.hasInitialSubscriptionName() ? cmdProducer.getInitialSubscriptionName() : null;
    final boolean supportsPartialProducer = supportsPartialProducer();
    TopicName topicName = validateTopicName(cmdProducer.getTopic(), requestId, cmdProducer);
    if (topicName == null) {
        return;
    }
    if (invalidOriginalPrincipal(originalPrincipal)) {
        final String msg = "Valid Proxy Client role should be provided while creating producer ";
        log.warn("[{}] {} with role {} and proxyClientAuthRole {} on topic {}", remoteAddress, msg, authRole, originalPrincipal, topicName);
        commandSender.sendErrorResponse(requestId, ServerError.AuthorizationError, msg);
        return;
    }
    CompletableFuture<Boolean> isAuthorizedFuture = isTopicOperationAllowed(topicName, TopicOperation.PRODUCE);
    if (!Strings.isNullOrEmpty(initialSubscriptionName)) {
        isAuthorizedFuture = isAuthorizedFuture.thenCombine(isTopicOperationAllowed(topicName, TopicOperation.SUBSCRIBE), (canProduce, canSubscribe) -> canProduce && canSubscribe);
    }
    isAuthorizedFuture.thenApply(isAuthorized -> {
        if (!isAuthorized) {
            String msg = "Client is not authorized to Produce";
            log.warn("[{}] {} with role {}", remoteAddress, msg, getPrincipal());
            ctx.writeAndFlush(Commands.newError(requestId, ServerError.AuthorizationError, msg));
            return null;
        }
        if (log.isDebugEnabled()) {
            log.debug("[{}] Client is authorized to Produce with role {}", remoteAddress, getPrincipal());
        }
        CompletableFuture<Producer> producerFuture = new CompletableFuture<>();
        CompletableFuture<Producer> existingProducerFuture = producers.putIfAbsent(producerId, producerFuture);
        if (existingProducerFuture != null) {
            if (existingProducerFuture.isDone() && !existingProducerFuture.isCompletedExceptionally()) {
                Producer producer = existingProducerFuture.getNow(null);
                log.info("[{}] Producer with the same id is already created:" + " producerId={}, producer={}", remoteAddress, producerId, producer);
                commandSender.sendProducerSuccessResponse(requestId, producer.getProducerName(), producer.getSchemaVersion());
                return null;
            } else {
                // There was an early request to create a producer with same producerId.
                // This can happen when client timeout is lower than the broker timeouts.
                // We need to wait until the previous producer creation request
                // either complete or fails.
                ServerError error = null;
                if (!existingProducerFuture.isDone()) {
                    error = ServerError.ServiceNotReady;
                } else {
                    error = getErrorCode(existingProducerFuture);
                    // remove producer with producerId as it's already completed with exception
                    producers.remove(producerId, existingProducerFuture);
                }
                log.warn("[{}][{}] Producer with id is already present on the connection, producerId={}", remoteAddress, topicName, producerId);
                commandSender.sendErrorResponse(requestId, error, "Producer is already present on the connection");
                return null;
            }
        }
        log.info("[{}][{}] Creating producer. producerId={}", remoteAddress, topicName, producerId);
        service.getOrCreateTopic(topicName.toString()).thenCompose((Topic topic) -> {
            // Before creating producer, check if backlog quota exceeded
            // on topic for size based limit and time based limit
            CompletableFuture<Void> backlogQuotaCheckFuture = CompletableFuture.allOf(topic.checkBacklogQuotaExceeded(producerName, BacklogQuotaType.destination_storage), topic.checkBacklogQuotaExceeded(producerName, BacklogQuotaType.message_age));
            backlogQuotaCheckFuture.thenRun(() -> {
                // Check whether the producer will publish encrypted messages or not
                if ((topic.isEncryptionRequired() || encryptionRequireOnProducer) && !isEncrypted) {
                    String msg = String.format("Encryption is required in %s", topicName);
                    log.warn("[{}] {}", remoteAddress, msg);
                    if (producerFuture.completeExceptionally(new ServerMetadataException(msg))) {
                        commandSender.sendErrorResponse(requestId, ServerError.MetadataError, msg);
                    }
                    producers.remove(producerId, producerFuture);
                    return;
                }
                disableTcpNoDelayIfNeeded(topicName.toString(), producerName);
                CompletableFuture<SchemaVersion> schemaVersionFuture = tryAddSchema(topic, schema);
                schemaVersionFuture.exceptionally(exception -> {
                    if (producerFuture.completeExceptionally(exception)) {
                        String message = exception.getMessage();
                        if (exception.getCause() != null) {
                            message += (" caused by " + exception.getCause());
                        }
                        commandSender.sendErrorResponse(requestId, BrokerServiceException.getClientErrorCode(exception), message);
                    }
                    producers.remove(producerId, producerFuture);
                    return null;
                });
                schemaVersionFuture.thenAccept(schemaVersion -> {
                    topic.checkIfTransactionBufferRecoverCompletely(isTxnEnabled).thenAccept(future -> {
                        CompletableFuture<Subscription> createInitSubFuture;
                        if (!Strings.isNullOrEmpty(initialSubscriptionName) && topic.isPersistent() && !topic.getSubscriptions().containsKey(initialSubscriptionName)) {
                            if (!this.getBrokerService().isAllowAutoSubscriptionCreation(topicName)) {
                                String msg = "Could not create the initial subscription due to the auto subscription " + "creation is not allowed.";
                                if (producerFuture.completeExceptionally(new BrokerServiceException.NotAllowedException(msg))) {
                                    log.warn("[{}] {} initialSubscriptionName: {}, topic: {}", remoteAddress, msg, initialSubscriptionName, topicName);
                                    commandSender.sendErrorResponse(requestId, ServerError.NotAllowedError, msg);
                                }
                                producers.remove(producerId, producerFuture);
                                return;
                            }
                            createInitSubFuture = topic.createSubscription(initialSubscriptionName, InitialPosition.Earliest, false);
                        } else {
                            createInitSubFuture = CompletableFuture.completedFuture(null);
                        }
                        createInitSubFuture.whenComplete((sub, ex) -> {
                            if (ex != null) {
                                String msg = "Failed to create the initial subscription: " + ex.getCause().getMessage();
                                log.warn("[{}] {} initialSubscriptionName: {}, topic: {}", remoteAddress, msg, initialSubscriptionName, topicName);
                                if (producerFuture.completeExceptionally(ex)) {
                                    commandSender.sendErrorResponse(requestId, BrokerServiceException.getClientErrorCode(ex), msg);
                                }
                                producers.remove(producerId, producerFuture);
                                return;
                            }
                            buildProducerAndAddTopic(topic, producerId, producerName, requestId, isEncrypted, metadata, schemaVersion, epoch, userProvidedProducerName, topicName, producerAccessMode, topicEpoch, supportsPartialProducer, producerFuture);
                        });
                    }).exceptionally(exception -> {
                        Throwable cause = exception.getCause();
                        log.error("producerId {}, requestId {} : TransactionBuffer recover failed", producerId, requestId, exception);
                        if (producerFuture.completeExceptionally(exception)) {
                            commandSender.sendErrorResponse(requestId, ServiceUnitNotReadyException.getClientErrorCode(cause), cause.getMessage());
                        }
                        producers.remove(producerId, producerFuture);
                        return null;
                    });
                });
            });
            return backlogQuotaCheckFuture;
        }).exceptionally(exception -> {
            Throwable cause = exception.getCause();
            if (cause instanceof BrokerServiceException.TopicBacklogQuotaExceededException) {
                BrokerServiceException.TopicBacklogQuotaExceededException tbqe = (BrokerServiceException.TopicBacklogQuotaExceededException) cause;
                IllegalStateException illegalStateException = new IllegalStateException(tbqe);
                BacklogQuota.RetentionPolicy retentionPolicy = tbqe.getRetentionPolicy();
                if (producerFuture.completeExceptionally(illegalStateException)) {
                    if (retentionPolicy == BacklogQuota.RetentionPolicy.producer_request_hold) {
                        commandSender.sendErrorResponse(requestId, ServerError.ProducerBlockedQuotaExceededError, illegalStateException.getMessage());
                    } else if (retentionPolicy == BacklogQuota.RetentionPolicy.producer_exception) {
                        commandSender.sendErrorResponse(requestId, ServerError.ProducerBlockedQuotaExceededException, illegalStateException.getMessage());
                    }
                }
                producers.remove(producerId, producerFuture);
                return null;
            }
            // Do not print stack traces for expected exceptions
            if (cause instanceof NoSuchElementException) {
                cause = new TopicNotFoundException("Topic Not Found.");
                log.info("[{}] Failed to load topic {}, producerId={}: Topic not found", remoteAddress, topicName, producerId);
            } else if (!Exceptions.areExceptionsPresentInChain(cause, ServiceUnitNotReadyException.class, ManagedLedgerException.class)) {
                log.error("[{}] Failed to create topic {}, producerId={}", remoteAddress, topicName, producerId, exception);
            }
            // client, only if not completed already.
            if (producerFuture.completeExceptionally(exception)) {
                commandSender.sendErrorResponse(requestId, BrokerServiceException.getClientErrorCode(cause), cause.getMessage());
            }
            producers.remove(producerId, producerFuture);
            return null;
        });
        return null;
    }).exceptionally(ex -> {
        logAuthException(remoteAddress, "producer", getPrincipal(), Optional.of(topicName), ex);
        commandSender.sendErrorResponse(requestId, ServerError.AuthorizationError, ex.getMessage());
        return null;
    });
}
Also used : CommandAuthResponse(org.apache.pulsar.common.api.proto.CommandAuthResponse) CommandUnsubscribe(org.apache.pulsar.common.api.proto.CommandUnsubscribe) ServiceUnitNotReadyException(org.apache.pulsar.broker.service.BrokerServiceException.ServiceUnitNotReadyException) CommandProducer(org.apache.pulsar.common.api.proto.CommandProducer) MessageIdData(org.apache.pulsar.common.api.proto.MessageIdData) ByteBufPair(org.apache.pulsar.common.protocol.ByteBufPair) StringUtils(org.apache.commons.lang3.StringUtils) ProtocolVersion(org.apache.pulsar.common.api.proto.ProtocolVersion) TxnID(org.apache.pulsar.client.api.transaction.TxnID) MLTransactionMetadataStore(org.apache.pulsar.transaction.coordinator.impl.MLTransactionMetadataStore) TopicOperation(org.apache.pulsar.common.policies.data.TopicOperation) MutableLong(org.apache.commons.lang3.mutable.MutableLong) Map(java.util.Map) BrokerInterceptor(org.apache.pulsar.broker.intercept.BrokerInterceptor) RestException(org.apache.pulsar.broker.web.RestException) NamespaceOperation(org.apache.pulsar.common.policies.data.NamespaceOperation) BaseCommand(org.apache.pulsar.common.api.proto.BaseCommand) CommandAck(org.apache.pulsar.common.api.proto.CommandAck) PositionImpl(org.apache.bookkeeper.mledger.impl.PositionImpl) InterceptException(org.apache.pulsar.common.intercept.InterceptException) CommandFlow(org.apache.pulsar.common.api.proto.CommandFlow) CommandConsumerStats(org.apache.pulsar.common.api.proto.CommandConsumerStats) ServerError(org.apache.pulsar.common.api.proto.ServerError) Set(java.util.Set) CommandNewTxn(org.apache.pulsar.common.api.proto.CommandNewTxn) StringUtils.isNotBlank(org.apache.commons.lang3.StringUtils.isNotBlank) BatchMessageIdImpl(org.apache.pulsar.client.impl.BatchMessageIdImpl) MessageMetadata(org.apache.pulsar.common.api.proto.MessageMetadata) SafeRun(org.apache.bookkeeper.mledger.util.SafeRun) SslHandler(io.netty.handler.ssl.SslHandler) AsyncCallbacks(org.apache.bookkeeper.mledger.AsyncCallbacks) ExceptionUtils(org.apache.commons.lang3.exception.ExceptionUtils) ClientCnx(org.apache.pulsar.client.impl.ClientCnx) ChannelOption(io.netty.channel.ChannelOption) SchemaRegistryService(org.apache.pulsar.broker.service.schema.SchemaRegistryService) AuthenticationState(org.apache.pulsar.broker.authentication.AuthenticationState) CommandGetTopicsOfNamespace(org.apache.pulsar.common.api.proto.CommandGetTopicsOfNamespace) TopicNotFoundException(org.apache.pulsar.broker.service.BrokerServiceException.TopicNotFoundException) SchemaType(org.apache.pulsar.common.schema.SchemaType) Commands(org.apache.pulsar.common.protocol.Commands) CommandCloseProducer(org.apache.pulsar.common.api.proto.CommandCloseProducer) Strings(com.google.common.base.Strings) SubType(org.apache.pulsar.common.api.proto.CommandSubscribe.SubType) ServerMetadataException(org.apache.pulsar.broker.service.BrokerServiceException.ServerMetadataException) SSLSession(javax.net.ssl.SSLSession) CommandGetOrCreateSchema(org.apache.pulsar.common.api.proto.CommandGetOrCreateSchema) ProtocolVersion.v5(org.apache.pulsar.common.api.proto.ProtocolVersion.v5) CommandGetSchema(org.apache.pulsar.common.api.proto.CommandGetSchema) SchemaInfoUtil(org.apache.pulsar.client.impl.schema.SchemaInfoUtil) CommandRedeliverUnacknowledgedMessages(org.apache.pulsar.common.api.proto.CommandRedeliverUnacknowledgedMessages) Metadata(org.apache.pulsar.common.naming.Metadata) Promise(io.netty.util.concurrent.Promise) AuthenticationProvider(org.apache.pulsar.broker.authentication.AuthenticationProvider) InitialPosition(org.apache.pulsar.common.api.proto.CommandSubscribe.InitialPosition) lombok.val(lombok.val) PulsarService(org.apache.pulsar.broker.PulsarService) KeySharedMode(org.apache.pulsar.common.api.proto.KeySharedMode) CommandEndTxnOnSubscription(org.apache.pulsar.common.api.proto.CommandEndTxnOnSubscription) CommandConnect(org.apache.pulsar.common.api.proto.CommandConnect) SchemaData(org.apache.pulsar.common.protocol.schema.SchemaData) ProducerAccessMode(org.apache.pulsar.common.api.proto.ProducerAccessMode) CommandLookupTopic(org.apache.pulsar.common.api.proto.CommandLookupTopic) MutableInt(org.apache.commons.lang3.mutable.MutableInt) SocketAddress(java.net.SocketAddress) CommandAddPartitionToTxn(org.apache.pulsar.common.api.proto.CommandAddPartitionToTxn) LoggerFactory(org.slf4j.LoggerFactory) AuthData(org.apache.pulsar.common.api.AuthData) Exceptions(org.apache.pulsar.functions.utils.Exceptions) AuthenticationException(javax.naming.AuthenticationException) KeyValue(org.apache.pulsar.common.api.proto.KeyValue) PersistentTopicsBase.unsafeGetPartitionedTopicMetadataAsync(org.apache.pulsar.broker.admin.impl.PersistentTopicsBase.unsafeGetPartitionedTopicMetadataAsync) CommandEndTxnOnPartition(org.apache.pulsar.common.api.proto.CommandEndTxnOnPartition) Preconditions.checkArgument(com.google.common.base.Preconditions.checkArgument) BacklogQuotaType(org.apache.pulsar.common.policies.data.BacklogQuota.BacklogQuotaType) Gauge(io.prometheus.client.Gauge) TxnAction(org.apache.pulsar.common.api.proto.TxnAction) NamespaceName(org.apache.pulsar.common.naming.NamespaceName) Schema(org.apache.pulsar.common.api.proto.Schema) TransactionMetadataStoreService(org.apache.pulsar.broker.TransactionMetadataStoreService) PulsarClientException(org.apache.pulsar.client.api.PulsarClientException) IdentityHashMap(java.util.IdentityHashMap) SubscriptionNotFoundException(org.apache.pulsar.broker.service.BrokerServiceException.SubscriptionNotFoundException) Position(org.apache.bookkeeper.mledger.Position) InetSocketAddress(java.net.InetSocketAddress) Collectors(java.util.stream.Collectors) CommandEndTxn(org.apache.pulsar.common.api.proto.CommandEndTxn) AuthenticationDataSource(org.apache.pulsar.broker.authentication.AuthenticationDataSource) Objects(java.util.Objects) ManagedLedgerException(org.apache.bookkeeper.mledger.ManagedLedgerException) MessageIdImpl(org.apache.pulsar.client.impl.MessageIdImpl) PersistentTopic(org.apache.pulsar.broker.service.persistent.PersistentTopic) FutureUtil(org.apache.pulsar.common.util.FutureUtil) PersistentSubscription(org.apache.pulsar.broker.service.persistent.PersistentSubscription) Optional(java.util.Optional) IncompatibleSchemaException(org.apache.pulsar.broker.service.schema.exceptions.IncompatibleSchemaException) PulsarHandler(org.apache.pulsar.common.protocol.PulsarHandler) CommandTcClientConnectRequest(org.apache.pulsar.common.api.proto.CommandTcClientConnectRequest) TopicName(org.apache.pulsar.common.naming.TopicName) CommandAddSubscriptionToTxn(org.apache.pulsar.common.api.proto.CommandAddSubscriptionToTxn) Entry(org.apache.bookkeeper.mledger.Entry) CommandSend(org.apache.pulsar.common.api.proto.CommandSend) BacklogQuota(org.apache.pulsar.common.policies.data.BacklogQuota) CompletableFuture(java.util.concurrent.CompletableFuture) TopicLookupBase.lookupTopicAsync(org.apache.pulsar.broker.lookup.TopicLookupBase.lookupTopicAsync) KeySharedMeta(org.apache.pulsar.common.api.proto.KeySharedMeta) CommandSubscribe(org.apache.pulsar.common.api.proto.CommandSubscribe) ChannelHandlerContext(io.netty.channel.ChannelHandlerContext) ByteBuf(io.netty.buffer.ByteBuf) CoordinatorException(org.apache.pulsar.transaction.coordinator.exceptions.CoordinatorException) FastThreadLocal(io.netty.util.concurrent.FastThreadLocal) CommandPartitionedTopicMetadata(org.apache.pulsar.common.api.proto.CommandPartitionedTopicMetadata) CommandSeek(org.apache.pulsar.common.api.proto.CommandSeek) ConsumerStatsImpl(org.apache.pulsar.common.policies.data.stats.ConsumerStatsImpl) NoSuchElementException(java.util.NoSuchElementException) CommandGetLastMessageId(org.apache.pulsar.common.api.proto.CommandGetLastMessageId) CommandUtils(org.apache.pulsar.common.protocol.CommandUtils) ManagedLedgerImpl(org.apache.bookkeeper.mledger.impl.ManagedLedgerImpl) AuthenticationDataCommand(org.apache.pulsar.broker.authentication.AuthenticationDataCommand) DEFAULT_CONSUMER_EPOCH(org.apache.pulsar.common.protocol.Commands.DEFAULT_CONSUMER_EPOCH) Logger(org.slf4j.Logger) Semaphore(java.util.concurrent.Semaphore) ServiceConfiguration(org.apache.pulsar.broker.ServiceConfiguration) FeatureFlags(org.apache.pulsar.common.api.proto.FeatureFlags) CommandCloseConsumer(org.apache.pulsar.common.api.proto.CommandCloseConsumer) SchemaVersion(org.apache.pulsar.common.protocol.schema.SchemaVersion) Commands.newLookupErrorResponse(org.apache.pulsar.common.protocol.Commands.newLookupErrorResponse) TimeUnit(java.util.concurrent.TimeUnit) HAProxyMessage(io.netty.handler.codec.haproxy.HAProxyMessage) ConcurrentLongHashMap(org.apache.pulsar.common.util.collections.ConcurrentLongHashMap) ConsumerBusyException(org.apache.pulsar.broker.service.BrokerServiceException.ConsumerBusyException) ChannelHandler(io.netty.channel.ChannelHandler) VisibleForTesting(com.google.common.annotations.VisibleForTesting) TransactionCoordinatorID(org.apache.pulsar.transaction.coordinator.TransactionCoordinatorID) Collections(java.util.Collections) SchemaData(org.apache.pulsar.common.protocol.schema.SchemaData) TopicNotFoundException(org.apache.pulsar.broker.service.BrokerServiceException.TopicNotFoundException) ServiceUnitNotReadyException(org.apache.pulsar.broker.service.BrokerServiceException.ServiceUnitNotReadyException) CompletableFuture(java.util.concurrent.CompletableFuture) ManagedLedgerException(org.apache.bookkeeper.mledger.ManagedLedgerException) ProducerAccessMode(org.apache.pulsar.common.api.proto.ProducerAccessMode) CommandLookupTopic(org.apache.pulsar.common.api.proto.CommandLookupTopic) PersistentTopic(org.apache.pulsar.broker.service.persistent.PersistentTopic) SchemaVersion(org.apache.pulsar.common.protocol.schema.SchemaVersion) ServerError(org.apache.pulsar.common.api.proto.ServerError) TopicName(org.apache.pulsar.common.naming.TopicName) CommandProducer(org.apache.pulsar.common.api.proto.CommandProducer) CommandCloseProducer(org.apache.pulsar.common.api.proto.CommandCloseProducer) ServerMetadataException(org.apache.pulsar.broker.service.BrokerServiceException.ServerMetadataException) MutableLong(org.apache.commons.lang3.mutable.MutableLong) NoSuchElementException(java.util.NoSuchElementException)

Aggregations

VisibleForTesting (com.google.common.annotations.VisibleForTesting)1 Preconditions.checkArgument (com.google.common.base.Preconditions.checkArgument)1 Strings (com.google.common.base.Strings)1 ByteBuf (io.netty.buffer.ByteBuf)1 ChannelHandler (io.netty.channel.ChannelHandler)1 ChannelHandlerContext (io.netty.channel.ChannelHandlerContext)1 ChannelOption (io.netty.channel.ChannelOption)1 HAProxyMessage (io.netty.handler.codec.haproxy.HAProxyMessage)1 SslHandler (io.netty.handler.ssl.SslHandler)1 FastThreadLocal (io.netty.util.concurrent.FastThreadLocal)1 Promise (io.netty.util.concurrent.Promise)1 Gauge (io.prometheus.client.Gauge)1 InetSocketAddress (java.net.InetSocketAddress)1 SocketAddress (java.net.SocketAddress)1 Collections (java.util.Collections)1 IdentityHashMap (java.util.IdentityHashMap)1 Map (java.util.Map)1 NoSuchElementException (java.util.NoSuchElementException)1 Objects (java.util.Objects)1 Optional (java.util.Optional)1