Rust::com Rust APIs Example app Optimize#556
Conversation
8484cc6 to
91acf6a
Compare
* Sync APIs added on this
9e5470a to
c4a5d19
Compare
* Updated example binary with proper structure * Kept only async test cases using tokio
c4a5d19 to
7d60e31
Compare
rpreddyhv
left a comment
There was a problem hiding this comment.
few comments & queries to clarify.
| - **Consumer Thread**: Receives and processes data independently | ||
|
|
||
| ### Async Operations | ||
| - Uses `futures::executor::block_on()` for async operations |
There was a problem hiding this comment.
Sloppy - block_on is synchronous. AI should elaborate more about the execution model instead of making obvious but inaccurate statements like here.
There was a problem hiding this comment.
Rephrased the statement.
|
|
||
| A separate test target (`tests_using_tokio_runtime.rs`) provides comprehensive integration tests using the **Tokio async runtime**. These tests are independent of the main application and use the `com-api-gen` generated types together with the `com_api` runtime, service discovery, and subscription APIs directly. | ||
|
|
||
| **Why Separate?** |
There was a problem hiding this comment.
I don't get how the points below answer this question.
There was a problem hiding this comment.
It was added to give impression why we have iteration test separately with tokio, so the simple reason for that is we do not want to use tokio in application and as we have already existing test case with tokio which can be used for quick and async runtime related testing.
| /// All execution modes supported by the example application. | ||
| /// Used by clap for CLI argument parsing and by the consumer/producer to select behaviour. | ||
| #[derive(clap::ValueEnum, Clone, Debug)] | ||
| pub enum ExampleType { |
There was a problem hiding this comment.
Why is this here? Imo that's clearly something that does not belong in a library but to the main CLI crate.
There was a problem hiding this comment.
Yes in first iteration of implementation, it was in main file and we were having different functions for each operation, but as it was calling separate function for each APIs so i thought to generalize and keep minimum function call from main and parsing can be done on library,
But I agree in that case sync execution is done with async function which is not proper way.
I have moved to the first iteration design.
| load("@rules_rust//rust:defs.bzl", "rust_binary", "rust_test") | ||
| load("@rules_rust//rust:defs.bzl", "rust_binary", "rust_library", "rust_test") | ||
|
|
||
| rust_library( |
There was a problem hiding this comment.
Please choose the 2024 edition.
| Err(e) => eprintln!("[SENDER] Failed to send sample: {:?}", e), | ||
| } | ||
| println!("[SENDER] Sent sample with pressure: {}", 1.0 + i as f32); | ||
| tokio::time::sleep(tokio::time::Duration::from_millis(1000)).await; |
There was a problem hiding this comment.
created const
| let mut buffer = SampleContainer::new(5); | ||
| for _ in 0..3 { | ||
| let (returned_buf, result) = if is_timeout { | ||
| let timeout = tokio::time::sleep(Duration::from_millis(1000)); |
There was a problem hiding this comment.
created const
| /// Polling interval between iterations in synchronous receive loops. | ||
| const SYNC_RECEIVE_POLL_INTERVAL_MS: u64 = 1000; | ||
|
|
||
| impl<R: Runtime> VehicleMonitorConsumer<R> { |
There was a problem hiding this comment.
Is there a reason why the impl block is separate from the type definition. Imo this only makes it harder to comprehend the logic.
There was a problem hiding this comment.
I was thinking to keep vehicleMonitor on separate module for better modularity but agreed to your point moved type into same file and removed vehicle_monitor file.
| let consumer_discovery = | ||
| runtime.find_service::<VehicleInterface>(FindServiceSpecifier::Specific(service_id)); | ||
| let instances = match mode { | ||
| ExampleType::Sync => consumer_discovery |
There was a problem hiding this comment.
Using a parameter to distinguish between sync and async doesn't make sense imo, as the call is enclosed in an async function in any case. I think you should split this into a sync and an async create function instead.
Now thinking about it, the definition of get_available_instances_async is odd: What's the async part of this method actually waiting for? Presence of at least one instance? If yes, then this behavior should be documented.
There was a problem hiding this comment.
Moved async and sync APIs in separate function and behavior is documented.
| /// | ||
| /// Takes `&self` to support all receive modes including streaming, | ||
| /// which requires exclusive access to the subscriber. | ||
| pub async fn read_tire_data(&self, mode: &ExampleType) -> Result<String> { |
There was a problem hiding this comment.
Same comment as in the new case: Having a sync code path in an async function isn't wrong (as log as it's nonblocking, which is the case), but kinda pointless: Why have the burden of an async function without any benefit?
There was a problem hiding this comment.
Agreed, it may give wrong impression to user as well, so moved async and sync function separately.
| Err(e) => Err(e), | ||
| } | ||
| } | ||
| _ => unreachable!( |
There was a problem hiding this comment.
Another code smell that reveals the non-ideal design here: This method isn't defined for all modes, which leads to mixing static and dynamic properties in this regard.
There was a problem hiding this comment.
As enum moved to main so now design is purely based on each APIs function call.
9a86f50 to
27c5215
Compare
ec2bd21 to
3fbbbd6
Compare
* Optimize the application * Remove VehicleMonitor and keep only lib * Keep enum parsing on main * Updated integration test
3fbbbd6 to
820b85b
Compare
#489