-
Notifications
You must be signed in to change notification settings - Fork 8
Expand file tree
/
Copy pathpr_comments.json
More file actions
25 lines (25 loc) · 12.6 KB
/
Copy pathpr_comments.json
File metadata and controls
25 lines (25 loc) · 12.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
{"body":"💡 **Suggestion**: `try_send` is great for the hot path. If the channel is full, we log a warning and block, which is safe, but we might want to monitor this channel's depth to ensure the background worker isn't consistently falling behind.","id":2972068838,"node_id":"PRRC_kwDOROfey86xJivm"}
{"body":"🟠 **Warning**: In the retry loop, `delay *= 2` can technically overflow `Duration` if `max_retries` was much higher. With `max_retries = 5` it's perfectly safe, but using `saturating_mul` or a cap is a good habit in these loops.","id":2972068844,"node_id":"PRRC_kwDOROfey86xJivs"}
{"body":"💡 **Suggestion**: For production, logging the dropped payload to a local 'dead letter' file when retries are exhausted would be a great next step to avoid permanent data loss during NATS outages.","id":2972068847,"node_id":"PRRC_kwDOROfey86xJivv"}
{"body":"💡 **Suggestion**: In `DomainEventDispatcher::dispatch`, the use of `try_send` with a fallback to `awaiting` on a full channel is good for durability, but it could still block the trade execution if NATS is down or slow. Consider whether we should drop events (with high-severity logging) or use a larger buffer if low latency is prioritized over total durability for these notifications.","id":2972068916,"node_id":"PRRC_kwDOROfey86xJiw0"}
{"body":"🟠 **Warning**: If the max retries are exceeded, the event is currently dropped. For a production trading system, we should ideally persist these to a local Dead Letter Queue (DLQ) file or database to ensure they can be re-published once the connectivity is restored.","id":2972068918,"node_id":"PRRC_kwDOROfey86xJiw2"}
{"body":"`dispatch` allocates/clones `subject` and `payload` for `try_send`, adding avoidable CPU/heap overhead. Consider constructing the message once and, on `TrySendError::Full(msg)`, reusing the owned `(subject, payload)` from the error to fall back without cloning.","id":2972071022,"node_id":"PRRC_kwDOROfey86xJjRu"}
{"body":"On a full channel, this falls back to `sender.send(...).await`, which can block the caller and add latency to the use-case path. If the goal is truly non-blocking critical-path behavior, consider an explicit non-blocking policy (drop with metrics, return an error, or buffer elsewhere) instead of awaiting here.","id":2972071031,"node_id":"PRRC_kwDOROfey86xJjR3"}
{"body":"The PR description/issue notes that NATS becomes the default publisher when the `nats` feature is enabled, but the only change here is adding the feature flag and modules; there’s no wiring in the binary/library to actually select `DomainEventDispatcher`/`NatsPublisherWorker` as the default `EventPublisher` implementation. If the intent is “feature provides the implementation but callers must wire it”, the description should be adjusted; otherwise, add the feature-gated initialization path.","id":2972071040,"node_id":"PRRC_kwDOROfey86xJjSA"}
{"body":"When `get_stream` succeeds, the worker assumes the stream is configured correctly, but doesn’t verify its subject list includes `\"{subject_prefix}.\u003e\"`. If the stream exists with different subjects, publishes will fail (\"no stream for subject\") and events will be retried/dropped; consider validating/updating subjects or returning a clear error.\n```suggestion\n Ok(stream) =\u003e {\n info!(\"Found existing JetStream stream: {}\", stream_name);\n\n // Validate that the existing stream is configured with the required subject.\n let required_subject = format!(\"{}.\u003e\", subject_prefix);\n let info = stream.info().await?;\n let has_required_subject = info\n .config\n .subjects\n .iter()\n .any(|s| s == \u0026required_subject);\n\n if !has_required_subject {\n error!(\n \"JetStream stream '{}' exists but is missing required subject '{}'\",\n stream_name, required_subject\n );\n return Err(format!(\n \"JetStream stream '{}' is misconfigured: missing subject '{}'\",\n stream_name, required_subject\n )\n .into());\n }\n```","id":2972071046,"node_id":"PRRC_kwDOROfey86xJjSG"}
{"body":"`publish_execution_failed` uses `sender.send(...).await` directly, bypassing the dispatcher’s overflow handling and potentially blocking the trade execution path under load. Consider routing this through `dispatch` (or applying the same `try_send`/policy) for consistent behavior.\n```suggestion\n self.dispatch(subject, \u0026payload)\n .await\n .map_err(crate::application::error::ApplicationError::EventPublishError)\n```","id":2972071055,"node_id":"PRRC_kwDOROfey86xJjSP"}
{"body":"The retry loop drops the event after max retries, but the issue/PR description claims dead-letter handling for persistent failures. If this PR is meant to close #25, implement an actual DLQ (or adjust the PR description/scope so it doesn’t claim that functionality).","id":2972071057,"node_id":"PRRC_kwDOROfey86xJjSR"}
{"body":"The integration test uses the Docker image tag `nats:latest`, which is non-deterministic and can cause future CI breakages when upstream releases change behavior. Pin to a specific NATS version tag (and ideally include it in documentation for reproducing the test).\n```suggestion\n // NOTE: Use a pinned NATS version for deterministic integration tests.\n let nats_image = GenericImage::new(\"nats\", \"2.10.18\")\n```","id":2972071063,"node_id":"PRRC_kwDOROfey86xJjSX"}
{"body":"Publishing uses `jetstream.publish(subject, payload)` without headers and always sends JSON strings. Issue #25’s acceptance criteria mention message headers (event_type/version/timestamp/correlation_id) and configurable JSON vs SBE serialization; none of that is implemented here. If the PR is meant to close #25, consider adding those fields/headers and a serializer abstraction, or update the scope/description accordingly.","id":2972071067,"node_id":"PRRC_kwDOROfey86xJjSb"}
{"body":"`publish_with_retry` contains core retry/backoff/drop behavior, but there are no unit tests for it (and the JetStream integration test is `#[ignore]`). Consider factoring the JetStream publish call behind a small trait so you can mock it and add deterministic tests for retry and max-retry handling.","id":2972071074,"node_id":"PRRC_kwDOROfey86xJjSi"}
{"body":"`write_to_dlq` appends to a hard-coded relative path (`nats_dlq.txt`). This can fail in deployments with a read-only/ephemeral working directory and can also leak potentially sensitive event payloads to local disk. Consider making the DLQ destination configurable (path/dir), rotating/limiting the file, or publishing failed messages to a dedicated JetStream subject/stream instead of writing to the current directory.","id":2972170541,"node_id":"PRRC_kwDOROfey86xJ7kt"}
{"body":"`dispatch` uses `try_send` and returns an error when the channel is full/closed. In the current application flow (e.g., `CreateRfqUseCase` persists the RFQ before publishing the event), propagating this error can cause the API/use-case to fail after state has already been committed. If the intent is to keep event publishing off the critical path, consider making this best-effort (log + return `Ok(())`), or switch to an outbox/transactional approach so persistence and publish failure semantics are consistent.\n```suggestion\n // Best-effort dispatch: log and continue without failing the use-case.\n }\n mpsc::error::TrySendError::Closed(returned_msg) =\u003e {\n tracing::error!(\n \"Event dispatcher channel closed. Action: {}\",\n returned_msg.0\n );\n // Best-effort dispatch: log and continue without failing the use-case.\n```","id":2972170551,"node_id":"PRRC_kwDOROfey86xJ7k3"}
{"body":"This test is `#[ignore]`, and the CI workflow currently runs `cargo test --all-features --lib`, which does not execute integration tests under `tests/` at all. As written, the JetStream publishing path won’t be exercised in CI. Consider either (1) moving the assertion into a lib test, (2) enabling integration tests in CI (e.g., `cargo test --all-features`), and/or (3) removing `#[ignore]` and provisioning NATS (service container) so the test can run reliably.\n```suggestion\nasync fn test_nats_jetstream_publishing() {\n // 1. Start NATS server with JetStream enabled\n let nats_image = GenericImage::new(\"nats\", \"2.10.18\")\n let nats_image = GenericImage::new(\"nats\", \"2.10.18\")\n```","id":2972170557,"node_id":"PRRC_kwDOROfey86xJ7k9"}
{"body":"PR description mentions the NATS JetStream publisher is “fully integrated”, but in the current codebase the only `nats`-gated items are `infrastructure::messaging::{dispatcher,nats_worker}` and there is no wiring that constructs a `DomainEventDispatcher`, starts a `NatsPublisherWorker`, or selects it as the application’s `EventPublisher`/`TradeEventPublisher` implementation. If this PR is meant to deliver end-to-end publishing when `--features nats` is enabled, add the runtime composition (e.g., in app bootstrap/config) to instantiate and run the worker and pass the dispatcher into the relevant use-cases/services.","id":2972170568,"node_id":"PRRC_kwDOROfey86xJ7lI"}
{"body":"The doc comment for `publish_with_retry` is duplicated (same sentence appears twice). Please remove one copy to avoid redundant rustdoc output.\n```suggestion\n\n```","id":2972170575,"node_id":"PRRC_kwDOROfey86xJ7lP"}
{"body":"Header extraction is looking for `metadata.event_type`, `metadata.version`, and a numeric `metadata.timestamp` (`as_u64()`), but the current `EventMetadata` only contains `event_id`, `rfq_id`, and `timestamp` (serialized via `Timestamp`/chrono as a string). As a result, these headers will never be set. Consider populating headers from the concrete event type at dispatch time (since the dispatcher already knows which publish_* method was called), and for timestamp use the RFC3339 string or convert `Timestamp` to unix millis explicitly before inserting.","id":2972170582,"node_id":"PRRC_kwDOROfey86xJ7lW"}
{"body":"Done. A check was added to connect that validates the existence of the expected '{prefix}.\u003e' subject.","id":2972176492,"node_id":"PRRC_kwDOROfey86xJ9Bs"}
{"body":"Done. A check was added to connect that validates the existence of the expected '{prefix}.\u003e' subject.","id":2972177513,"node_id":"PRRC_kwDOROfey86xJ9Rp"}
{"body":"`connect` treats any `get_stream` error as “stream not found” and attempts to create the stream. This can mask real problems (e.g., auth/permission errors, temporary network errors, JetStream disabled) and lead to confusing logs or unintended stream creation attempts. Consider distinguishing “not found” from other errors and returning the original error for non-NotFound cases.","id":2972187863,"node_id":"PRRC_kwDOROfey86xJ_zX"}
{"body":"The integration test uses a fixed durable consumer name (`\"test_consumer\"`) with a fixed stream (`\"TEST_STREAM\"`). If the test is re-run against a persisted JetStream state (or a previous run didn’t fully clean up), `create_consumer` can fail due to the durable already existing. Consider using a unique durable name per run (e.g., include a UUID) and/or deleting the consumer/stream during test teardown.","id":2972187879,"node_id":"PRRC_kwDOROfey86xJ_zn"}
{"body":"`test_write_to_dlq` writes to a hard-coded relative path (`nats_dlq.txt`). Since Rust tests run in parallel by default, this can be flaky if other tests (or another run) touches the same file, and it can also leave artifacts when the test fails mid-run. Consider writing to a unique temp file/directory (e.g., via `tempfile`) or setting `NATS_DLQ_PATH` to a per-test path.\n```suggestion\n use std::env;\n use tempfile::NamedTempFile;\n #[tokio::test]\n async fn test_write_to_dlq() {\n let subject = \"test.dlq.subject\";\n let payload = r#\"{\"test\":\"dlq_payload\"}\"#;\n\n // Use a unique temporary file for this test's DLQ path to avoid interference.\n let temp_file = NamedTempFile::new().unwrap();\n let dlq_path = temp_file.path().to_string_lossy().to_string();\n env::set_var(\"NATS_DLQ_PATH\", \u0026dlq_path);\n\n let result = NatsPublisherWorker::write_to_dlq(subject, payload).await;\n assert!(result.is_ok());\n\n let contents = tokio::fs::read_to_string(\u0026dlq_path).await.unwrap();\n assert!(contents.contains(\u0026format!(\"[{}] {}\\n\", subject, payload)));\n```","id":2972187899,"node_id":"PRRC_kwDOROfey86xJ_z7"}