zhaohai666 opened a new pull request, #1380:
URL: https://github.com/apache/rocketmq-clients/pull/1380

   # feat(csharp): implement LiteSimpleConsumer
   
   ## Summary
   
   This PR ports the **LiteSimpleConsumer** from the reference Java client to 
the .NET client
   (RocketMQ 5.x gRPC protocol), branch `feat/csharp-lite-simple-consumer` 
based on `master`
   (`fc088d4a`). It lands **1 commit** touching **14 files (+1,124 / −37)**.
   
   The lite consumer model lets one consumer group consume many short-lived 
"lite topics" that all map
   onto a single parent topic. The consumer binds to the parent topic, then 
dynamically subscribes /
   unsubscribes individual lite topics through the `SyncLiteSubscription` RPC, 
and pulls their messages
   explicitly with `Receive` + `Ack`.
   
   **What is included**
   
   - `LiteSimpleConsumer` + `ILiteSimpleConsumer`: `SubscribeLite(liteTopic)`,
     `SubscribeLite(liteTopic, OffsetOption)`, `UnsubscribeLite(liteTopic)`, 
`GetLiteTopicSet()`,
     `GetBindTopic()`, plus the inherited `SimpleConsumer` receive / ack / 
change-invisible-duration
     APIs, and a `Builder` with the same validation rules as the Java builder.
   - `LiteSimpleSubscriptionSettings`: simple-consumer settings that report
     `ClientType.LITE_SIMPLE_CONSUMER`, so the server derives `LITE_SELECTIVE` 
consumption mode.
   - `ClientType`: new `LiteSimpleConsumer` member mapped to the protobuf enum.
   - `LiteSubscriptionManager`: generalized from `PushConsumer` to the 
`Consumer` base class so both
     lite consumer kinds share it, and given `Shutdown()` to dispose the 
periodic sync timer.
   - `Consumer`: shared `CheckRunning()` / `GetRequestTimeout()` / `Namespace` /
     `SyncLiteSubscription(request, timeout)`; `PushConsumer` now overrides 
them instead of duplicating
     the code. `IsLiteConsumer()` also recognizes 
`LiteSimpleSubscriptionSettings`.
   - `MessageView`: exposes `LiteTopic` parsed from the message system 
properties.
   - `SubscriptionLoadBalancer`: throws `NotFoundException` instead of dividing 
by zero when a route
     carries no queue.
   - A defect fix on the lite ack path (see below).
   
   ---
   
   ## Defect fix: missing `liteTopic` in ack / change-invisible-duration 
requests
   
   Real-cluster testing showed that messages were received correctly but every 
`Ack` failed with
   `50001 INTERNAL_SERVER_ERROR`. The proxy resolves LMQ receipt handles 
through the `liteTopic`
   carried in `AckMessageEntry` / `ChangeInvisibleDurationRequest`; the plain 
`SimpleConsumer` path
   never set it, so the proxy could not map the receipt handle back to the 
parent topic.
   
   The fix mirrors `ConsumerImpl.wrapAckMessageRequest` on the Java side:
   `LiteSimpleConsumer` overrides `WrapAckMessageRequest` and 
`WrapChangeInvisibleDuration` and sets
   `LiteTopic` whenever `MessageView.LiteTopic` is present. Without it, no lite 
consumer built on the
   simple-consumer path can acknowledge messages.
   
   ---
   
   ## Tests
   
   **Offline unit tests** — 20/20 passing (`dotnet test --filter 
FullyQualifiedName~LiteSimpleConsumerTest`):
   
   - Builder / constructor: missing client config, invalid or blank consumer 
group, blank bind topic,
     non-positive await duration, missing required options.
   - Protocol: settings and heartbeat carry `LITE_SIMPLE_CONSUMER`; 
`SubscribeLite` issues a
     `PARTIAL_ADD` sync; duplicate subscribe short-circuits without an RPC; 
`UnsubscribeLite` issues a
     `PARTIAL_REMOVE`; unknown topic unsubscribe is a no-op; blank lite topic 
rejected;
     `NOTIFY_UNSUBSCRIBE_LITE` command removes the topic locally.
   - Ack path: `Ack` and `ChangeInvisibleDuration` requests carry `liteTopic`, 
and omit it for a
     non-lite message.
   - Routing: only the first readable master queue is kept; an empty route 
raises `NotFoundException`.
   - Life cycle: `SubscribeLite` / `UnsubscribeLite` before startup fail fast.
   
   **Real-cluster integration tests** — 3/3 passing against a local RocketMQ 
5.5.1 deployment
   (namesrv + broker with `enableLmq=true` and `enableMultiDispatch=true`, 
standalone **proxy in
   CLUSTER mode**, parent topic created with `message.type=LITE`, consumer 
group pre-created with
   `+lite.bind.topic=<parentTopic>`):
   
   - `TestReceiveAndAckLiteMessages`: send 5 lite messages → `SubscribeLite` 
with
     `OffsetOption.MinOffset` → receive → assert `liteTopic` on every message → 
ack all.
   - `TestDeliverMessagesSentAfterSubscribeLite`: messages sent after the 
subscription are delivered.
   - `TestStopDeliveringAfterUnsubscribeLite`: no delivery after 
`UnsubscribeLite`.
   
   The integration suite is guarded by the `ROCKETMQ_CSHARP_LITE_ENDPOINTS` 
environment variable and
   reports `Assert.Inconclusive` when it is not set, so CI without a cluster 
stays green.
   The broker log confirms the consumer registers as `CONSUME_ACTIVELY 
LITE_SELECTIVE`.
   
   ---
   
   ## Example
   
   `csharp/examples/LiteSimpleConsumerExample.cs` (wired into 
`examples/QuickStart.cs`): produces 5
   lite messages with `Message.Builder.SetLiteTopic`, subscribes with 
`OffsetOption.MinOffset`,
   receives and acks them, then unsubscribes to release the quota.
   
   ---
   
   ## Checklist
   
   - [x] Reference implementation (`java/client/.../LiteSimpleConsumerImpl`) 
reviewed and mirrored
   - [x] `dotnet build` clean, no new compiler warnings
   - [x] Offline unit tests pass (20/20)
   - [x] Real-cluster integration tests pass (3/3)
   - [x] No changes to generated protobuf bindings required 
(`SyncLiteSubscription`,
         `AckMessageEntry#lite_topic`, `ClientType.LITE_SIMPLE_CONSUMER` 
already present)
   - [x] Example added and executed against a local cluster
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to