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

   ### Which Issue(s) This PR Fixes
   
   Fixes #1408
   
   ### Brief Description
   
   **Scenario.** The server grants a `LitePushConsumer` a lite subscription 
quota (e.g. `lite_subscription_quota = 2000`) and a `max_lite_topic_size` 
through the `Settings` telemetry command. It can also revoke a lite topic with 
`NotifyUnsubscribeLiteCommand`. Applications that create one lite topic per 
session/user/device rely on the client rejecting subscriptions beyond the 
quota. The Java client does this locally with code `42902`. The Rust client 
never applied any of these server settings:
   
   1. `PushConsumer::start_with_telemetry` ignored the channel passed in by 
`LitePushConsumer` (`_telemetry_command_tx`) and created its own. The lite 
telemetry handler saw a closed channel and exited right after startup. No 
`Settings` or `NotifyUnsubscribeLiteCommand` ever reached 
`LiteSubscriptionManager`.
   2. The quota therefore stayed at its initial value `0`, and 
`check_lite_subscription_quota` treated `0` as "not known yet, allow". The 
quota check was effectively disabled. Startup also never waited for the server 
settings, so even with (1) fixed, subscriptions made right after `start()` 
would bypass the check.
   
   Against a real server pushing quota 2000, all 2010 `subscribe_lite` calls 
succeeded. Java rejects the 2001st.
   
   This PR aligns `LitePushConsumer` with the Java client:
   
   | Java | This PR |
   |---|---|
   | `LitePushConsumerImpl#onSettingsCommand` calls 
`super.onSettingsCommand(...)` and then 
`liteSubscriptionManager.sync(settings)`. `#onNotifyUnsubscribeLiteCommand` 
calls `liteSubscriptionManager.onNotifyUnsubscribeLiteCommand(...)` | 
**`start_with_telemetry` forwards every telemetry command** to the caller's 
channel after the push consumer has handled it (retry policy), so the existing 
lite handler receives `Settings` and `NotifyUnsubscribeLiteCommand` |
   | `ClientImpl#startUp` waits on `ClientSessionImpl#settingsInitFuture`, 
which is completed by the first `Settings` and times out after 
`SETTINGS_INITIALIZATION_TIMEOUT` (3 s) + request timeout, failing the startup 
| **`LitePushConsumer::start` waits for the first `Settings`**, bounded by 3 s 
+ `ClientOption::timeout()`. On timeout it shuts down and returns an error, 
using the existing start-failure path. `LiteSubscriptionManager` gains a 
`watch`-based `wait_for_initial_settings`, completed by any `Settings` command, 
as in Java |
   | `LitePushConsumerImpl#startUp` runs `liteSubscriptionManager.startUp()` 
after `super.startUp()` | **`LiteSubscriptionManager::start` (first 
`CompleteAdd` sync) now runs after the settings are applied**. Before, it ran 
before the lite handler was even spawned |
   | `LiteSubscriptionManager#checkLiteSubscriptionQuota` is 
`liteTopicSet.size() + delta > liteSubscriptionQuota`, with no special case for 
`0` | **Removed the `quota == 0` → allow branch** |
   
   Other notes for reviewers:
   
   1. **`lite_subscription_manager` is now compiled in unit tests.** In 
`lib.rs` it was gated by `#[cfg(not(test))]`, so its existing tests 
(`test_validate_lite_topic`, `test_check_quota`) never ran. 
`lite_push_consumer` stays gated, because it cannot be built against the mocked 
`Client`. #1381 makes the same change.
   2. **Behavior change.** If the server does not push `Settings` within 3 s + 
request timeout, `LitePushConsumer::start` now fails instead of starting with 
an unknown quota. This matches Java. In our test, the first `Settings` arrived 
0.3 s after startup began.
   3. **Overlap with other PRs.**
      - #1381 (LiteSimpleConsumer) adds a similar `wait_for_initial_settings` 
to `LiteSubscriptionManager`, but only for `LiteSimpleConsumer`, and on timeout 
it logs a warning and continues. Whichever lands second will need a small 
rebase. I'm happy to adapt.
      - #1404 touches the telemetry loop in `push_consumer.rs`, but not 
`start_with_telemetry`.
   4. **Out of scope.** Server-pushed push-consumer settings (fifo, batch size, 
...) are not applied by `super.onSettingsCommand` in Rust. That is handled by 
#1404.
   
   ### How Did You Test This Change?
   
   **Unit tests.** Each new test fails without the corresponding change:
   
   - `push_consumer::tests::test_start_with_telemetry_forwards_commands`: it 
pushes `Settings` (quota 2000, max 64) and `NotifyUnsubscribeLiteCommand` into 
the client's command channel, then asserts both arrive on the channel passed to 
`start_with_telemetry`. Before the fix, `recv()` returns `None`.
   - `lite_subscription_manager::tests::test_check_quota`: with quota `0`, 
`delta = 1` is rejected with code `42902`. It fails with the old `quota == 0` 
branch.
   - `test_wait_for_initial_settings`: times out before `Settings`, returns 
immediately after, and quota and max size are updated.
   - `test_wait_for_initial_settings_wakes_up_waiter`: a pending waiter is 
woken by a `Settings` without a subscription.
   - `test_scheduler_clone_shares_initial_settings_state`: the scheduler clone 
shares the initialization state and the quota.
   
   ```
   $ cargo test
   test result: ok. 95 passed; 0 failed; 1 ignored   (lib; master: 89)
   test result: ok. 3 passed; 0 failed               (lite_integration_test)
   test result: ok. 2 passed; 0 failed; 3 ignored    (doc-tests)
   $ cargo fmt --check                                  # clean
   $ RUSTDOCFLAGS="--cfg docsrs" cargo doc --no-deps --all-features   # no 
warnings
   $ cargo build --examples                             # ok
   ```
   
   `cargo clippy --all-features -- -D warnings` fails on `master` with 2 
`for_kv_map` errors in `rust/src/client.rs` (lines 904 and 912). They are 
unchanged here, and this PR adds no new clippy findings in library code.
   
   **End-to-end**, against a managed RocketMQ 5 server that pushes 
`lite_subscription_quota = 2000` and `max_lite_topic_size = 64`, with a 
`LitePushConsumer` subscribing 2010 distinct lite topics:
   
   | | before | after |
   |---|---|---|
   | `subscribe_lite` result | all 2010 succeed | 2000 succeed; the 2001st 
fails with `Lite subscription quota exceeded: current=2000, delta=1, 
quota=2000` (code `42902`) |
   | `Updated lite subscription quota to 2000` | never logged | logged before 
`starts successfully`, and again on every Settings refresh |
   | lite telemetry handler | stops in the same millisecond as startup | runs 
until `shutdown()` |
   
   The Java client 5.2.2 behaves the same way as the "after" column against the 
same instance, group and topic.
   
   The e2e run was done on top of #1407. Without it, `LitePushConsumer` cannot 
receive messages from this server at all. The changes in this PR are 
independent of #1407.
   


-- 
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