未验证 提交 6eefee7b 编写于 作者: H Hao Zhang 提交者: GitHub

[Issue 7759] Support set Max Consumer on topic level. (#7968)

Fix [https://github.com/apache/pulsar/issues/7759](https://github.com/apache/pulsar/issues/7759), and master issue [https://github.com/apache/pulsar/issues/2688](https://github.com/apache/pulsar/issues/2688)

### Motivation

Support set/get/remove maxConsumers on a topic level.
上级 97ba09e6
......@@ -2407,20 +2407,14 @@ public class PersistentTopicsBase extends AdminResource {
return pulsar().getTopicPoliciesService().updateTopicPoliciesAsync(topicName, topicPolicies.get());
}
protected void internalGetPersistence(AsyncResponse asyncResponse){
protected Optional<PersistencePolicies> internalGetPersistence(){
validateAdminAccessForTenant(namespaceName.getTenant());
validatePoliciesReadOnlyAccess();
if (topicName.isGlobal()) {
validateGlobalNamespaceOwnership(namespaceName);
}
checkTopicLevelPolicyEnable();
Optional<PersistencePolicies> persistencePolicies = getTopicPolicies(topicName)
.map(TopicPolicies::getPersistence);
if (!persistencePolicies.isPresent()) {
asyncResponse.resume(Response.noContent().build());
}else {
asyncResponse.resume(persistencePolicies.get());
}
return getTopicPolicies(topicName).map(TopicPolicies::getPersistence);
}
protected CompletableFuture<Void> internalSetPersistence(PersistencePolicies persistencePolicies) {
......@@ -2452,20 +2446,14 @@ public class PersistentTopicsBase extends AdminResource {
return pulsar().getTopicPoliciesService().updateTopicPoliciesAsync(topicName, topicPolicies.get());
}
protected void internalGetMaxProducers(AsyncResponse asyncResponse) {
protected Optional<Integer> internalGetMaxProducers() {
validateAdminAccessForTenant(namespaceName.getTenant());
validatePoliciesReadOnlyAccess();
if (topicName.isGlobal()) {
validateGlobalNamespaceOwnership(namespaceName);
}
checkTopicLevelPolicyEnable();
Optional<Integer> maxProducers = getTopicPolicies(topicName)
.map(TopicPolicies::getMaxProducerPerTopic);
if (!maxProducers.isPresent()) {
asyncResponse.resume(Response.noContent().build());
} else {
asyncResponse.resume(maxProducers.get());
}
return getTopicPolicies(topicName).map(TopicPolicies::getMaxProducerPerTopic);
}
protected CompletableFuture<Void> internalSetMaxProducers(Integer maxProducers) {
......@@ -2499,6 +2487,47 @@ public class PersistentTopicsBase extends AdminResource {
return pulsar().getTopicPoliciesService().updateTopicPoliciesAsync(topicName, topicPolicies.get());
}
protected Optional<Integer> internalGetMaxConsumers() {
validateAdminAccessForTenant(namespaceName.getTenant());
validatePoliciesReadOnlyAccess();
if (topicName.isGlobal()) {
validateGlobalNamespaceOwnership(namespaceName);
}
checkTopicLevelPolicyEnable();
return getTopicPolicies(topicName).map(TopicPolicies::getMaxConsumerPerTopic);
}
protected CompletableFuture<Void> internalSetMaxConsumers(Integer maxConsumers) {
validateAdminAccessForTenant(namespaceName.getTenant());
validatePoliciesReadOnlyAccess();
if (topicName.isGlobal()) {
validateGlobalNamespaceOwnership(namespaceName);
}
checkTopicLevelPolicyEnable();
if (maxConsumers < 0) {
throw new RestException(Status.PRECONDITION_FAILED,
"maxConsumers must be 0 or more");
}
TopicPolicies topicPolicies = getTopicPolicies(topicName).orElseGet(TopicPolicies::new);
topicPolicies.setMaxConsumerPerTopic(maxConsumers);
return pulsar().getTopicPoliciesService().updateTopicPoliciesAsync(topicName, topicPolicies);
}
protected CompletableFuture<Void> internalRemoveMaxConsumers() {
validateAdminAccessForTenant(namespaceName.getTenant());
validatePoliciesReadOnlyAccess();
if (topicName.isGlobal()) {
validateGlobalNamespaceOwnership(namespaceName);
}
checkTopicLevelPolicyEnable();
Optional<TopicPolicies> topicPolicies = getTopicPolicies(topicName);
if (!topicPolicies.isPresent()) {
return CompletableFuture.completedFuture(null);
}
topicPolicies.get().setMaxConsumerPerTopic(null);
return pulsar().getTopicPoliciesService().updateTopicPoliciesAsync(topicName, topicPolicies.get());
}
protected MessageId internalTerminate(boolean authoritative) {
if (topicName.isGlobal()) {
validateGlobalNamespaceOwnership(namespaceName);
......
......@@ -56,11 +56,11 @@ import org.apache.pulsar.client.impl.MessageIdImpl;
import org.apache.pulsar.common.partition.PartitionedTopicMetadata;
import org.apache.pulsar.common.policies.data.AuthAction;
import org.apache.pulsar.common.policies.data.BacklogQuota;
import org.apache.pulsar.common.policies.data.DelayedDeliveryPolicies;
import org.apache.pulsar.common.policies.data.DispatchRate;
import org.apache.pulsar.common.policies.data.InactiveTopicPolicies;
import org.apache.pulsar.common.policies.data.PersistencePolicies;
import org.apache.pulsar.common.policies.data.DelayedDeliveryPolicies;
import org.apache.pulsar.common.policies.data.OffloadPolicies;
import org.apache.pulsar.common.policies.data.PersistencePolicies;
import org.apache.pulsar.common.policies.data.PersistentOfflineTopicStats;
import org.apache.pulsar.common.policies.data.PersistentTopicInternalStats;
import org.apache.pulsar.common.policies.data.PublishRate;
......@@ -1558,7 +1558,12 @@ public class PersistentTopics extends PersistentTopicsBase {
@PathParam("topic") @Encoded String encodedTopic) {
validateTopicName(tenant, namespace, encodedTopic);
try {
internalGetPersistence(asyncResponse);
Optional<PersistencePolicies> persistencePolicies = internalGetPersistence();
if (!persistencePolicies.isPresent()) {
asyncResponse.resume(Response.noContent().build());
} else {
asyncResponse.resume(persistencePolicies.get());
}
} catch (RestException e) {
asyncResponse.resume(e);
} catch (Exception e) {
......@@ -1640,7 +1645,12 @@ public class PersistentTopics extends PersistentTopicsBase {
@PathParam("topic") @Encoded String encodedTopic) {
validateTopicName(tenant, namespace, encodedTopic);
try {
internalGetMaxProducers(asyncResponse);
Optional<Integer> maxProducers = internalGetMaxProducers();
if (!maxProducers.isPresent()) {
asyncResponse.resume(Response.noContent().build());
} else {
asyncResponse.resume(maxProducers.get());
}
} catch (RestException e) {
asyncResponse.resume(e);
} catch (Exception e) {
......@@ -1706,6 +1716,90 @@ public class PersistentTopics extends PersistentTopicsBase {
});
}
@GET
@Path("/{tenant}/{namespace}/{topic}/maxConsumers")
@ApiOperation(value = "Get maxConsumers config for specified topic.")
@ApiResponses(value = {@ApiResponse(code = 403, message = "Don't have admin permission"),
@ApiResponse(code = 404, message = "Topic does not exist"),
@ApiResponse(code = 405, message = "Topic level policy is disabled, to enable the topic level policy and retry"),
@ApiResponse(code = 409, message = "Concurrent modification")})
public void getMaxConsumers(@Suspended final AsyncResponse asyncResponse,
@PathParam("tenant") String tenant,
@PathParam("namespace") String namespace,
@PathParam("topic") @Encoded String encodedTopic) {
validateTopicName(tenant, namespace, encodedTopic);
try {
Optional<Integer> maxConsumers = internalGetMaxConsumers();
if (!maxConsumers.isPresent()) {
asyncResponse.resume(Response.noContent().build());
} else {
asyncResponse.resume(maxConsumers.get());
}
} catch (RestException e) {
asyncResponse.resume(e);
} catch (Exception e) {
asyncResponse.resume(new RestException(e));
}
}
@POST
@Path("/{tenant}/{namespace}/{topic}/maxConsumers")
@ApiOperation(value = "Set maxConsumers config for specified topic.")
@ApiResponses(value = {@ApiResponse(code = 403, message = "Don't have admin permission"),
@ApiResponse(code = 404, message = "Topic does not exist"),
@ApiResponse(code = 405, message = "Topic level policy is disabled, to enable the topic level policy and retry"),
@ApiResponse(code = 409, message = "Concurrent modification"),
@ApiResponse(code = 412, message = "Invalid value of maxConsumers")})
public void setMaxConsumers(@Suspended final AsyncResponse asyncResponse,
@PathParam("tenant") String tenant,
@PathParam("namespace") String namespace,
@PathParam("topic") @Encoded String encodedTopic,
@ApiParam(value = "The max consumers of the topic") int maxConsumers) {
validateTopicName(tenant, namespace, encodedTopic);
internalSetMaxConsumers(maxConsumers).whenComplete((r, ex) -> {
if (ex instanceof RestException) {
log.error("Failed updated persistence policies", ex);
asyncResponse.resume(ex);
} else if (ex != null) {
log.error("Failed updated persistence policies", ex);
asyncResponse.resume(new RestException(ex));
} else {
log.info("[{}] Successfully updated max consumers: namespace={}, topic={}, maxConsumers={}",
clientAppId(),
namespaceName,
topicName.getLocalName(),
maxConsumers);
asyncResponse.resume(Response.noContent().build());
}
});
}
@DELETE
@Path("/{tenant}/{namespace}/{topic}/maxConsumers")
@ApiOperation(value = "Remove maxConsumers config for specified topic.")
@ApiResponses(value = {@ApiResponse(code = 403, message = "Don't have admin permission"),
@ApiResponse(code = 404, message = "Topic does not exist"),
@ApiResponse(code = 405, message = "Topic level policy is disabled, to enable the topic level policy and retry"),
@ApiResponse(code = 409, message = "Concurrent modification")})
public void removeMaxConsumers(@Suspended final AsyncResponse asyncResponse,
@PathParam("tenant") String tenant,
@PathParam("namespace") String namespace,
@PathParam("topic") @Encoded String encodedTopic) {
validateTopicName(tenant, namespace, encodedTopic);
internalRemoveMaxConsumers().whenComplete((r, ex) -> {
if (ex != null) {
log.error("Failed to remove maxConsumers", ex);
asyncResponse.resume(new RestException(ex));
} else {
log.info("[{}] Successfully remove max consumers: namespace={}, topic={}",
clientAppId(),
namespaceName,
topicName.getLocalName());
asyncResponse.resume(Response.noContent().build());
}
});
}
@POST
@Path("/{tenant}/{namespace}/{topic}/terminate")
......
......@@ -165,21 +165,29 @@ public abstract class AbstractTopic implements Topic {
}
protected boolean isConsumersExceededOnTopic() {
Policies policies;
try {
// Use getDataIfPresent from zk cache to make the call non-blocking and prevent deadlocks
policies = brokerService.pulsar().getConfigurationCache().policiesCache()
.getDataIfPresent(AdminResource.path(POLICIES, TopicName.get(topic).getNamespace()));
Integer maxConsumers = null;
TopicPolicies topicPolicies = getTopicPolicies(TopicName.get(topic));
if (topicPolicies != null) {
maxConsumers = topicPolicies.getMaxConsumerPerTopic();
}
if (maxConsumers == null) {
Policies policies;
try {
// Use getDataIfPresent from zk cache to make the call non-blocking and prevent deadlocks
policies = brokerService.pulsar().getConfigurationCache().policiesCache()
.getDataIfPresent(AdminResource.path(POLICIES, TopicName.get(topic).getNamespace()));
if (policies == null) {
if (policies == null) {
policies = new Policies();
}
} catch (Exception e) {
log.warn("[{}] Failed to get namespace policies that include max number of consumers: {}", topic,
e.getMessage());
policies = new Policies();
}
} catch (Exception e) {
log.warn("[{}] Failed to get namespace policies that include max number of consumers: {}", topic,
e.getMessage());
policies = new Policies();
maxConsumers = policies.max_consumers_per_topic;
}
final int maxConsumersPerTopic = policies.max_consumers_per_topic > 0 ? policies.max_consumers_per_topic
final int maxConsumersPerTopic = maxConsumers > 0 ? maxConsumers
: brokerService.pulsar().getConfiguration().getMaxConsumersPerTopic();
if (maxConsumersPerTopic > 0 && maxConsumersPerTopic <= getNumberOfConsumers()) {
return true;
......
......@@ -209,4 +209,22 @@ public class TopicPoliciesDisableTest extends MockedPulsarServiceBaseTest {
Assert.assertEquals(e.getStatusCode(), 405);
}
}
@Test
public void testMaxConsumersDisabled() {
log.info("MaxConsumers will set to the topic: {}", testTopic);
try {
admin.topics().setMaxConsumers(testTopic, 2);
Assert.fail();
} catch (PulsarAdminException e) {
Assert.assertEquals(e.getStatusCode(), 405);
}
try {
admin.topics().getMaxConsumers(testTopic);
Assert.fail();
} catch (PulsarAdminException e) {
Assert.assertEquals(e.getStatusCode(), 405);
}
}
}
......@@ -28,6 +28,7 @@ import org.apache.pulsar.broker.service.BacklogQuotaManager;
import org.apache.pulsar.broker.service.Topic;
import org.apache.pulsar.broker.service.persistent.PersistentTopic;
import org.apache.pulsar.client.admin.PulsarAdminException;
import org.apache.pulsar.client.api.Consumer;
import org.apache.pulsar.client.api.Producer;
import org.apache.pulsar.client.api.PulsarClientException;
import org.apache.pulsar.common.naming.TopicName;
......@@ -590,4 +591,121 @@ public class TopicPoliciesTest extends MockedPulsarServiceBaseTest {
admin.topics().deletePartitionedTopic(testTopic, true);
}
@Test
public void testCheckMaxConsumers() throws Exception {
Integer maxProducers = new Integer(-1);
log.info("MaxConsumers: {} will set to the topic: {}", maxProducers, testTopic);
try {
admin.topics().setMaxConsumers(testTopic, maxProducers);
Assert.fail();
} catch (PulsarAdminException e) {
Assert.assertEquals(e.getStatusCode(), 412);
}
admin.topics().deletePartitionedTopic(testTopic, true);
}
@Test
public void testSetMaxConsumers() throws Exception {
admin.namespaces().setMaxConsumersPerTopic(myNamespace, 1);
log.info("MaxConsumers: {} will set to the namespace: {}", 1, myNamespace);
Integer maxConsumers = 2;
log.info("MaxConsumers: {} will set to the topic: {}", maxConsumers, persistenceTopic);
admin.topics().setMaxConsumers(persistenceTopic, maxConsumers);
Thread.sleep(3000);
admin.topics().createPartitionedTopic(persistenceTopic, 2);
Consumer consumer1 = null;
Consumer consumer2 = null;
Consumer consumer3 = null;
try {
consumer1 = pulsarClient.newConsumer().subscriptionName("sub1").topic(persistenceTopic).subscribe();
} catch (PulsarClientException e) {
Assert.fail();
}
try {
consumer2 = pulsarClient.newConsumer().subscriptionName("sub2").topic(persistenceTopic).subscribe();
} catch (PulsarClientException e) {
Assert.fail();
}
try {
consumer3 = pulsarClient.newConsumer().subscriptionName("sub3").topic(persistenceTopic).subscribe();
Assert.fail();
} catch (PulsarClientException e) {
log.info("Topic reached max consumers limit");
}
Assert.assertNotNull(consumer1);
Assert.assertNotNull(consumer2);
Assert.assertNull(consumer3);
consumer1.close();
consumer2.close();
Integer getMaxConsumers = admin.topics().getMaxConsumers(persistenceTopic);
log.info("MaxConsumers {} get on topic: {}", getMaxConsumers, persistenceTopic);
Assert.assertEquals(getMaxConsumers, maxConsumers);
admin.topics().deletePartitionedTopic(persistenceTopic, true);
admin.topics().deletePartitionedTopic(testTopic, true);
}
@Test
public void testRemoveMaxConsumers() throws Exception {
Integer maxConsumers = 2;
log.info("maxConsumers: {} will set to the topic: {}", maxConsumers, persistenceTopic);
admin.topics().setMaxConsumers(persistenceTopic, maxConsumers);
Thread.sleep(3000);
admin.topics().createPartitionedTopic(persistenceTopic, 2);
Consumer consumer1 = null;
Consumer consumer2 = null;
Consumer consumer3 = null;
Consumer consumer4 = null;
try {
consumer1 = pulsarClient.newConsumer().subscriptionName("sub1").topic(persistenceTopic).subscribe();
} catch (PulsarClientException e) {
Assert.fail();
}
try {
consumer2 = pulsarClient.newConsumer().subscriptionName("sub2").topic(persistenceTopic).subscribe();
} catch (PulsarClientException e) {
Assert.fail();
}
try {
consumer3 = pulsarClient.newConsumer().subscriptionName("sub3").topic(persistenceTopic).subscribe();
Assert.fail();
} catch (PulsarClientException e) {
log.info("Topic reached max consumers limit on topic level.");
}
Assert.assertNotNull(consumer1);
Assert.assertNotNull(consumer2);
Assert.assertNull(consumer3);
admin.topics().removeMaxConsumers(persistenceTopic);
Thread.sleep(3000);
Integer getMaxConsumers = admin.topics().getMaxConsumers(testTopic);
log.info("MaxConsumers: {} get on topic: {} after remove", getMaxConsumers, testTopic);
Assert.assertNull(getMaxConsumers);
try {
consumer3 = pulsarClient.newConsumer().subscriptionName("sub3").topic(persistenceTopic).subscribe();
} catch (PulsarClientException e) {
Assert.fail();
}
Assert.assertNotNull(consumer3);
admin.namespaces().setMaxConsumersPerTopic(myNamespace, 3);
log.info("MaxConsumers: {} will set to the namespace: {}", 3, myNamespace);
try {
consumer4 = pulsarClient.newConsumer().subscriptionName("sub4").topic(persistenceTopic).subscribe();
Assert.fail();
} catch (PulsarClientException e) {
log.info("Topic reached max consumers limit on namespace level.");
}
Assert.assertNull(consumer4);
consumer1.close();
consumer2.close();
consumer3.close();
admin.topics().deletePartitionedTopic(persistenceTopic, true);
admin.topics().deletePartitionedTopic(testTopic, true);
}
}
......@@ -2212,4 +2212,57 @@ public interface Topics {
* @param topic Topic name
*/
CompletableFuture<Void> removeMaxProducersAsync(String topic);
/**
* Get the max number of consumer for specified topic.
*
* @param topic Topic name
* @return Configuration of bookkeeper persistence policies
* @throws PulsarAdminException Unexpected error
*/
Integer getMaxConsumers(String topic) throws PulsarAdminException;
/**
* Get the max number of consumer for specified topic asynchronously.
*
* @param topic Topic name
* @return Configuration of bookkeeper persistence policies
* @throws PulsarAdminException Unexpected error
*/
CompletableFuture<Integer> getMaxConsumersAsync(String topic);
/**
* Set the max number of consumer for specified topic.
*
* @param topic Topic name
* @param maxConsumers Max number of consumer
* @throws PulsarAdminException Unexpected error
*/
void setMaxConsumers(String topic, int maxConsumers) throws PulsarAdminException;
/**
* Set the max number of consumer for specified topic asynchronously.
*
* @param topic Topic name
* @param maxConsumers Max number of consumer
* @throws PulsarAdminException Unexpected error
*/
CompletableFuture<Void> setMaxConsumersAsync(String topic, int maxConsumers);
/**
* Remove the max number of consumer for specified topic.
*
* @param topic Topic name
* @throws PulsarAdminException Unexpected error
*/
void removeMaxConsumers(String topic) throws PulsarAdminException;
/**
* Remove the max number of consumer for specified topic asynchronously.
*
* @param topic Topic name
*/
CompletableFuture<Void> removeMaxConsumersAsync(String topic);
}
......@@ -2391,6 +2391,81 @@ public class TopicsImpl extends BaseResource implements Topics {
return asyncDeleteRequest(path);
}
@Override
public Integer getMaxConsumers(String topic) throws PulsarAdminException {
try {
return getMaxConsumersAsync(topic).get(this.readTimeoutMs, TimeUnit.MILLISECONDS);
} catch (ExecutionException e) {
throw (PulsarAdminException) e.getCause();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new PulsarAdminException(e);
} catch (TimeoutException e) {
throw new PulsarAdminException.TimeoutException(e);
}
}
@Override
public CompletableFuture<Integer> getMaxConsumersAsync(String topic) {
TopicName tn = validateTopic(topic);
WebTarget path = topicPath(tn, "maxConsumers");
final CompletableFuture<Integer> future = new CompletableFuture<>();
asyncGetRequest(path,
new InvocationCallback<Integer>() {
@Override
public void completed(Integer maxProducers) {
future.complete(maxProducers);
}
@Override
public void failed(Throwable throwable) {
future.completeExceptionally(getApiException(throwable.getCause()));
}
});
return future;
}
@Override
public void setMaxConsumers(String topic, int maxConsumers) throws PulsarAdminException {
try {
setMaxConsumersAsync(topic, maxConsumers).get(this.readTimeoutMs, TimeUnit.MILLISECONDS);
} catch (ExecutionException e) {
throw (PulsarAdminException) e.getCause();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new PulsarAdminException(e);
} catch (TimeoutException e) {
throw new PulsarAdminException.TimeoutException(e);
}
}
@Override
public CompletableFuture<Void> setMaxConsumersAsync(String topic, int maxConsumers) {
TopicName tn = validateTopic(topic);
WebTarget path = topicPath(tn, "maxConsumers");
return asyncPostRequest(path, Entity.entity(maxConsumers, MediaType.APPLICATION_JSON));
}
@Override
public void removeMaxConsumers(String topic) throws PulsarAdminException {
try {
removeMaxConsumersAsync(topic).get(this.readTimeoutMs, TimeUnit.MILLISECONDS);
} catch (ExecutionException e) {
throw (PulsarAdminException) e.getCause();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new PulsarAdminException(e);
} catch (TimeoutException e) {
throw new PulsarAdminException.TimeoutException(e);
}
}
@Override
public CompletableFuture<Void> removeMaxConsumersAsync(String topic) {
TopicName tn = validateTopic(topic);
WebTarget path = topicPath(tn, "maxConsumers");
return asyncDeleteRequest(path);
}
private static final Logger log = LoggerFactory.getLogger(TopicsImpl.class);
}
......@@ -147,12 +147,15 @@ public class CmdTopics extends CmdBase {
jcommander.addCommand("get-publish-rate", new GetPublishRate());
jcommander.addCommand("set-publish-rate", new SetPublishRate());
jcommander.addCommand("remove-publish-rate", new RemovePublishRate());
jcommander.addCommand("get-maxProducers", new GetMaxProducers());
jcommander.addCommand("set-maxProducers", new SetMaxProducers());
jcommander.addCommand("remove-maxProducers", new RemoveMaxProducers());
jcommander.addCommand("get-max-producers", new GetMaxProducers());
jcommander.addCommand("set-max-producers", new SetMaxProducers());
jcommander.addCommand("remove-max-producers", new RemoveMaxProducers());
jcommander.addCommand("get-inactive-topic-policies", new GetInactiveTopicPolicies());
jcommander.addCommand("set-inactive-topic-policies", new SetInactiveTopicPolicies());
jcommander.addCommand("remove-inactive-topic-policies", new RemoveInactiveTopicPolicies());
jcommander.addCommand("get-max-consumers", new GetMaxConsumers());
jcommander.addCommand("set-max-consumers", new SetMaxConsumers());
jcommander.addCommand("remove-max-consumers", new RemoveMaxConsumers());
}
@Parameters(commandDescription = "Get the list of topics under a namespace.")
......@@ -1471,7 +1474,7 @@ public class CmdTopics extends CmdBase {
@Override
void run() throws PulsarAdminException {
String persistentTopic = validatePersistentTopic(params);
admin.topics().getMaxProducers(persistentTopic);
print(admin.topics().getMaxProducers(persistentTopic));
}
}
......@@ -1563,4 +1566,43 @@ public class CmdTopics extends CmdBase {
admin.topics().removeInactiveTopicPolicies(persistentTopic);
}
}
@Parameters(commandDescription = "Get max number of consumers for a topic")
private class GetMaxConsumers extends CliCommand {
@Parameter(description = "persistent://tenant/namespace/topic", required = true)
private java.util.List<String> params;
@Override
void run() throws PulsarAdminException {
String persistentTopic = validatePersistentTopic(params);
print(admin.topics().getMaxConsumers(persistentTopic));
}
}
@Parameters(commandDescription = "Set max number of consumers for a topic")
private class SetMaxConsumers extends CliCommand {
@Parameter(description = "persistent://tenant/namespace/topic", required = true)
private java.util.List<String> params;
@Parameter(names = { "--max-consumers", "-c" }, description = "Max consumers for a topic", required = true)
private int maxConsumers;
@Override
void run() throws PulsarAdminException {
String persistentTopic = validatePersistentTopic(params);
admin.topics().setMaxConsumers(persistentTopic, maxConsumers);
}
}
@Parameters(commandDescription = "Remove max number of consumers for a topic")
private class RemoveMaxConsumers extends CliCommand {
@Parameter(description = "persistent://tenant/namespace/topic", required = true)
private java.util.List<String> params;
@Override
void run() throws PulsarAdminException {
String persistentTopic = validatePersistentTopic(params);
admin.topics().removeMaxConsumers(persistentTopic);
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册