All Products
Search
Document Center

ApsaraMQ for RocketMQ:Consumer types

Last Updated:Mar 11, 2026

ApsaraMQ for RocketMQ provides two consumer types: Push consumer and Simple consumer. Each type handles message acquisition, concurrency, and retries differently. Choose the type that matches your processing model and reliability requirements.

Which consumer type to use

ScenarioRecommended typeReason
Predictable processing time, no custom threadingPush consumerThe SDK manages message fetching, concurrency, and retries. Register a listener, process each message, and return the result.
Variable processing time, custom workflowsSimple consumerYour application controls when to fetch messages, how to distribute them across threads, and when to acknowledge completion.
Note

Switching consumer types does not affect existing ApsaraMQ for RocketMQ resources or business processing.

Message processing stages

Both consumer types follow a three-stage lifecycle:

  1. Receive -- Fetch messages from the server.

  2. Process -- Run business logic on each message.

  3. Commit -- Report the result (success or failure) to the server.

Message consumption flow

The two types differ in how each stage is handled:

FeaturePush consumerSimple consumer
InterfaceListener callback -- implement logic inside the listener and return a resultApplication calls API operations to receive, process, and acknowledge messages
ConcurrencySDK-managedApplication-managed
FlexibilityHighly encapsulated, less flexibleAtomic operations, highly customizable
Best forStandard consumption with predictable processing timeCustom workflows, async distribution, or batch consumption
SDK classesPushConsumer, LitePushConsumerSimpleConsumer

Push consumers

A Push consumer encapsulates message fetching, threading, and retry logic. Register a message listener during initialization, and the SDK handles the rest.

How it works

The SDK uses a Reactor thread model internally:

  1. A built-in long-polling thread pulls messages from the server asynchronously.

  2. Messages are placed into an internal cache queue.

  3. The SDK dispatches messages to consumer threads, which invoke your listener.

PushConsumer internal mechanism

Listener results

The message listener must return one of the following results:

ResultJava SDK constantBehavior
SuccessConsumeResult.SUCCESSThe server updates the consumption progress.
FailureConsumeResult.FAILUREThe system retries based on the PushConsumer retry policy.
Exception thrown(treated as failure)Same retry behavior as an explicit failure.

Timeout behavior

If processing logic blocks and prevents the message from completing within the allowed time, the SDK forcibly submits a failure result and handles the message according to the retry policy.

Note

A timeout causes the SDK to submit a failure result, but the current processing thread may not respond to the interruption and can continue running.

Reliability constraints

The Push consumer determines success or failure strictly from the listener return value. To preserve this guarantee:

  1. Process synchronously. Complete all processing before returning the result.

  2. Do not redistribute messages. Do not hand off messages to other threads and return a result before those threads finish.

If the listener returns success before processing completes and processing later fails, the server considers the message consumed and does not retry.

Ordered message delivery

When a consumer group uses ordered consumption mode, the Push consumer invokes the listener in strict message order with no additional configuration. For more information, see Ordered messages.

Note

Ordered delivery requires synchronous processing. Custom async distribution inside the listener voids the ordering guarantee.

When to use Push consumers

Push consumers work best when:

  • Processing time is predictable. Unpredictable durations trigger frequent timeouts, which cause duplicate messages through retries.

  • Standard consumption is sufficient. The SDK controls the thread model and delivers messages at maximum throughput. This simplifies development but does not support async processing or custom rate control.

SDK classes

ApsaraMQ for RocketMQ provides two SDK classes for Push consumers:

  • PushConsumer -- Consumes messages from standard (non-Lite) topics.

  • LitePushConsumer -- Consumes messages from Lite-type topics, with consumption control at the Lite topic granularity.

PushConsumer example

// Consume normal messages with PushConsumer
ClientServiceProvider provider = ClientServiceProvider.loadService();
String topic = "<your-topic>";
FilterExpression filterExpression = new FilterExpression("<your-filter-tag>", FilterExpressionType.TAG);

PushConsumer pushConsumer = provider.newPushConsumerBuilder()
        // Set the consumer group
        .setConsumerGroup("<your-consumer-group>")
        // Set the access endpoint
        .setClientConfiguration(ClientConfiguration.newBuilder().setEndpoints("<your-endpoint>").build())
        // Bind the subscription
        .setSubscriptionExpressions(Collections.singletonMap(topic, filterExpression))
        // Register the message listener
        .setMessageListener(new MessageListener() {
            @Override
            public ConsumeResult consume(MessageView messageView) {
                // Process the message and return the result
                return ConsumeResult.SUCCESS;
            }
        })
        .build();

Replace the following placeholders with your actual values:

PlaceholderDescriptionExample
<your-topic>Topic nameorder-events
<your-filter-tag>Message tag for filteringpayment
<your-consumer-group>Consumer group nameorder-service-group
<your-endpoint>Server access endpoint--

LitePushConsumer example

// Consume normal messages with LitePushConsumer
ClientServiceProvider provider = ClientServiceProvider.loadService();

LitePushConsumer litePushConsumer = provider.newLitePushConsumerBuilder()
        // Set the access endpoint
        .setClientConfiguration(ClientConfiguration.newBuilder().setEndpoints("<your-endpoint>").build())
        // Set the topic
        .bindTopic("<your-topic>")
        // Set the consumer group
        .setConsumerGroup("<your-consumer-group>")
        // Register the message listener
        .setMessageListener(messageView -> {
            // Process the message and return the result
            return ConsumeResult.SUCCESS;
        })
        .build();

// Subscribe to Lite topics
litePushConsumer.subscribeLite("<your-lite-topic-1>");
litePushConsumer.subscribeLite("<your-lite-topic-2>");

Simple consumers

A Simple consumer provides atomic API operations for message processing. Your application controls message fetching, thread management, and acknowledgment directly.

How it works

  1. Call ReceiveMessage to pull a batch of messages from the server.

  2. Distribute messages to your business threads for processing.

  3. Call AckMessage for each successfully processed message.

If processing fails, do not send an acknowledgment. The message becomes available again after the message invisibility duration expires, triggering a retry. For more information, see SimpleConsumer retry policy.

API operations

OperationPurposeKey parameters
ReceiveMessagePull messages from the serverBatch size: number of messages per request. Message invisibility duration: maximum processing time before the message is redelivered.
AckMessageAcknowledge successful consumptionNone
ChangeInvisibleDurationExtend processing time for a message already receivedMessage invisibility duration: new value, typically used when processing takes longer than initially expected.
Note

The server uses distributed storage, so ReceiveMessage may return an empty result even when messages exist. To handle this, call ReceiveMessage again or increase call concurrency.

Failure handling

The following table describes how different failure scenarios affect message delivery:

Failure scenarioBehavior
Processing fails (no ACK sent)The message becomes visible again after the invisibility duration expires. The server redelivers it for retry.
Processing exceeds the invisibility durationSame as no ACK -- the message becomes visible and is redelivered. Use ChangeInvisibleDuration to extend the processing window before the duration expires.
Consumer crashes before sending ACKThe message is redelivered after the invisibility duration expires.

Ordered message delivery

A Simple consumer processes ordered messages in storage order. For a group of messages that must stay in sequence, the next message cannot be retrieved until the preceding one is processed.

When to use Simple consumers

Simple consumers work best when:

  • Processing time is unpredictable. Specify an initial message invisibility duration when calling ReceiveMessage, then extend it with ChangeInvisibleDuration if needed.

  • Custom workflows are required. The SDK imposes no threading model -- implement async distribution, batch consumption, or any custom pattern.

  • Rate control matters. Your code decides when and how often to call ReceiveMessage, providing direct control over throughput.

SDK class

ApsaraMQ for RocketMQ provides one SDK class for Simple consumers: SimpleConsumer. This class cannot consume messages from Lite topics.

SimpleConsumer example

// Consume normal messages with SimpleConsumer
ClientServiceProvider provider = ClientServiceProvider.loadService();
String topic = "<your-topic>";
FilterExpression filterExpression = new FilterExpression("<your-filter-tag>", FilterExpressionType.TAG);

SimpleConsumer simpleConsumer = provider.newSimpleConsumerBuilder()
        // Set the consumer group
        .setConsumerGroup("<your-consumer-group>")
        // Set the access endpoint
        .setClientConfiguration(ClientConfiguration.newBuilder().setEndpoints("<your-endpoint>").build())
        // Bind the subscription
        .setSubscriptionExpressions(Collections.singletonMap(topic, filterExpression))
        .build();

try {
    // Pull up to 10 messages, wait up to 30 seconds
    List<MessageView> messageViewList = simpleConsumer.receive(10, Duration.ofSeconds(30));
    messageViewList.forEach(messageView -> {
        System.out.println(messageView);
        // Acknowledge each message after successful processing
        try {
            simpleConsumer.ack(messageView);
        } catch (ClientException e) {
            e.printStackTrace();
        }
    });
} catch (ClientException e) {
    // Handle failures such as throttling, then retry the receive call
    e.printStackTrace();
}

Best practices

Control processing time for Push consumers

Keep message processing within the timeout threshold. Frequent timeouts cause unnecessary retries and duplicate messages. If your application regularly handles long-running tasks, switch to a Simple consumer and set an appropriate message invisibility duration.