Skip to content

Conversation

@smypmsa
Copy link
Member

@smypmsa smypmsa commented Jun 11, 2025

Promoting to production

This PR promotes all changes from dev to master.

Changes included

Summary by CodeRabbit

  • New Features

    • Introduced a new metric to track WebSocket log latency for Transfer events on multiple EVM-compatible blockchains.
  • Bug Fixes

    • Added timeout configuration for HTTP requests to improve reliability.
    • Improved error handling for WebSocket connections.
  • Tests

    • Updated test configuration to use the correct handler for local development server.
  • Chores

    • Updated metric selection across multiple blockchain integrations to use the new log latency metric.

@smypmsa smypmsa self-assigned this Jun 11, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jun 11, 2025

Walkthrough

This update introduces the new WSLogLatencyMetric class in metrics/ethereum.py for measuring log latency via WebSocket subscriptions to USDT Transfer events. All API read modules are switched from WSBlockLatencyMetric to WSLogLatencyMetric. Supporting changes include improved error handling, HTTP timeout configuration, and updated test imports.

Changes

Files Change Summary
api/read/arbitrum.py, api/read/base.py, api/read/bnbsc.py, api/read/ethereum.py Switched metric import and usage from WSBlockLatencyMetric to WSLogLatencyMetric in the METRICS list.
metrics/ethereum.py Added new WSLogLatencyMetric class for log latency measurement; updated WSBlockLatencyMetric logging.
common/base_metric.py Imported websockets.exceptions for improved exception handling.
common/metric_types.py Added HTTP request timeout to HttpCallLatencyMetricBase's fetch_data method.
tests/test_api_read.py Changed handler import to use api.read.bnbsc.handler in test server setup.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant WSLogLatencyMetric
    participant WebSocket
    participant HTTPNode

    Client->>WSLogLatencyMetric: collect_metric()
    WSLogLatencyMetric->>WebSocket: Connect & subscribe to USDT Transfer logs
    WebSocket-->>WSLogLatencyMetric: Emit first Transfer log event
    WSLogLatencyMetric->>HTTPNode: Fetch block timestamp for log's block number
    HTTPNode-->>WSLogLatencyMetric: Return block timestamp
    WSLogLatencyMetric->>WSLogLatencyMetric: Calculate latency (now - block timestamp)
    WSLogLatencyMetric-->>Client: Update metric value
    WSLogLatencyMetric->>WebSocket: Unsubscribe & close connection
Loading

Possibly related PRs

Poem

In the warren of code where metrics hop,
A new log latency bunny takes the top!
No more block waits, just Transfer event chimes,
With WebSockets and HTTP, it measures the times.
A hop, a skip, and a latency check—
This rabbit’s metrics are now truly tech!
🐇✨

✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@vercel
Copy link

vercel bot commented Jun 11, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
chainstack-rpc-dashboard-germany ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jun 11, 2025 1:43pm
chainstack-rpc-dashboard-singapore ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jun 11, 2025 1:43pm
chainstack-rpc-dashboard-us-west ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jun 11, 2025 1:43pm

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (10)
api/read/arbitrum.py (2)

12-14: Drop commented-out import to keep module clean

Keeping dead code around quickly turns these files into changelog graveyards. Removing the commented line makes the intent explicit and avoids accidental re-enablement during bulk edits.

-from metrics.ethereum import (
-    # WSBlockLatencyMetric,
-    WSLogLatencyMetric,
-)
+from metrics.ethereum import WSLogLatencyMetric

18-21: Prune leftover entry in METRICS list

Same reasoning—commented items add noise and can mislead readers/linters.

-METRICS = [
-    # (WSBlockLatencyMetric, metric_name),
-    (WSLogLatencyMetric, metric_name),
+METRICS = [
+    (WSLogLatencyMetric, metric_name),
api/read/ethereum.py (2)

10-12: Remove obsolete import comment

Mirror the cleanup applied to Arbitrum to stay consistent.

-from metrics.ethereum import (
-    # WSBlockLatencyMetric,
-    WSLogLatencyMetric,
-)
+from metrics.ethereum import WSLogLatencyMetric

16-19: Tidy METRICS – scrap commented tuple

-METRICS = [
-    # (WSBlockLatencyMetric, metric_name),
-    (WSLogLatencyMetric, metric_name),
+METRICS = [
+    (WSLogLatencyMetric, metric_name),
api/read/base.py (2)

11-14: One-liner import is clearer

-from metrics.ethereum import (
-    # WSBlockLatencyMetric,
-    WSLogLatencyMetric,
-)
+from metrics.ethereum import WSLogLatencyMetric

18-21: Trim commented metric entry

-METRICS = [
-    # (WSBlockLatencyMetric, metric_name),
-    (WSLogLatencyMetric, metric_name),
+METRICS = [
+    (WSLogLatencyMetric, metric_name),
common/base_metric.py (2)

11-11: Import only what you need

websockets.exceptions is imported solely to reference InvalidStatusCode. Import that symbol directly and drop the extra module import to avoid namespace clutter.

-import websockets.exceptions
+from websockets.exceptions import InvalidStatusCode

114-116: Update reference after scoped import

If applying the previous suggestion, adjust the type check accordingly:

-        if isinstance(error, websockets.exceptions.InvalidStatusCode):
+        if isinstance(error, InvalidStatusCode):
metrics/ethereum.py (2)

265-270: Add ClassVar annotation to mutable class attribute.

The TOKEN_CONTRACTS dictionary should be annotated with typing.ClassVar to clarify it's a class-level attribute and prevent accidental instance-level modifications.

Add the import at the top of the file:

from typing import ClassVar

Then update the attribute declaration:

-    TOKEN_CONTRACTS: dict[str, str] = {
+    TOKEN_CONTRACTS: ClassVar[dict[str, str]] = {
🧰 Tools
🪛 Ruff (0.11.9)

265-270: Mutable class attributes should be annotated with typing.ClassVar

(RUF012)


307-330: Improve exception chaining for better error tracking.

The timeout helper methods are well-implemented, but exception chaining should be improved for better debugging.

-        except asyncio.TimeoutError:
-            raise TimeoutError(
-                f"WebSocket message send timed out after {timeout} seconds"
-            )
+        except asyncio.TimeoutError as e:
+            raise TimeoutError(
+                f"WebSocket message send timed out after {timeout} seconds"
+            ) from e

And similarly for recv_with_timeout:

-        except asyncio.TimeoutError:
-            raise TimeoutError(
-                f"WebSocket message reception timed out after {timeout} seconds"
-            )
+        except asyncio.TimeoutError as e:
+            raise TimeoutError(
+                f"WebSocket message reception timed out after {timeout} seconds"
+            ) from e
🧰 Tools
🪛 Ruff (0.11.9)

307-307: Missing type annotation for function argument websocket

(ANN001)


312-314: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


316-316: Missing type annotation for function argument websocket

(ANN001)


323-323: Line too long (101 > 88)

(E501)


327-329: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dda17dc and 74d6f33.

📒 Files selected for processing (8)
  • api/read/arbitrum.py (1 hunks)
  • api/read/base.py (1 hunks)
  • api/read/bnbsc.py (1 hunks)
  • api/read/ethereum.py (1 hunks)
  • common/base_metric.py (1 hunks)
  • common/metric_types.py (1 hunks)
  • metrics/ethereum.py (3 hunks)
  • tests/test_api_read.py (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (5)
api/read/bnbsc.py (1)
metrics/ethereum.py (1)
  • WSLogLatencyMetric (257-475)
api/read/base.py (1)
metrics/ethereum.py (1)
  • WSLogLatencyMetric (257-475)
api/read/arbitrum.py (1)
metrics/ethereum.py (1)
  • WSLogLatencyMetric (257-475)
api/read/ethereum.py (1)
metrics/ethereum.py (1)
  • WSLogLatencyMetric (257-475)
metrics/ethereum.py (5)
common/metric_config.py (6)
  • get_prometheus_labels (86-88)
  • MetricLabels (65-111)
  • MetricConfig (37-50)
  • get_label (106-111)
  • MetricLabelKey (8-16)
  • update_label (90-96)
common/metric_types.py (8)
  • WebSocketMetric (19-84)
  • subscribe (37-38)
  • unsubscribe (41-42)
  • listen_for_data (45-46)
  • collect_metric (58-84)
  • collect_metric (98-109)
  • connect (48-56)
  • process_data (233-235)
api/read/ethereum.py (1)
  • handler (28-29)
common/base_metric.py (6)
  • collect_metric (49-50)
  • update_metric_value (82-91)
  • mark_success (93-95)
  • mark_failure (97-102)
  • handle_error (104-131)
  • process_data (53-54)
metrics/solana_landing_rate.py (1)
  • process_data (185-186)
🪛 Ruff (0.11.9)
metrics/ethereum.py

165-165: Line too long (101 > 88)

(E501)


265-270: Mutable class attributes should be annotated with typing.ClassVar

(RUF012)


277-277: Missing docstring in __init__

(D107)


283-283: Missing type annotation for **kwargs

(ANN003)


307-307: Missing type annotation for function argument websocket

(ANN001)


312-314: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


316-316: Missing type annotation for function argument websocket

(ANN001)


323-323: Line too long (101 > 88)

(E501)


327-329: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


331-331: Missing type annotation for function argument websocket

(ANN001)


357-357: Missing type annotation for function argument websocket

(ANN001)


378-378: Missing type annotation for function argument websocket

(ANN001)


378-378: Dynamically typed expressions (typing.Any) are disallowed in listen_for_data

(ANN401)

🔇 Additional comments (11)
tests/test_api_read.py (1)

31-33: Import path update looks correct

The switch to api.read.bnbsc.handler aligns the dev-server script with the new metric implementation. No further issues spotted.

api/read/bnbsc.py (1)

12-13: LGTM! Successful migration to log-based latency metrics.

The switch from WSBlockLatencyMetric to WSLogLatencyMetric is properly implemented with correct import and metric registration.

Also applies to: 19-20

common/metric_types.py (1)

178-180: Good addition of explicit timeout configuration.

Adding the timeout to the ClientSession ensures HTTP requests don't hang indefinitely and properly respect the configured timeout value.

metrics/ethereum.py (8)

7-9: Imports correctly added for the new functionality.

The Optional type hint and aiohttp library are properly imported to support the new WSLogLatencyMetric implementation.


161-167: Useful addition of WebSocket message size logging.

The message size logging provides valuable insights for monitoring WebSocket communication overhead.

🧰 Tools
🪛 Ruff (0.11.9)

165-165: Line too long (101 > 88)

(E501)


277-305: Well-structured initialization with proper fallback handling.

The constructor properly initializes the WebSocket metric with blockchain-specific token contracts and includes a sensible fallback to Ethereum USDT.

🧰 Tools
🪛 Ruff (0.11.9)

277-277: Missing docstring in __init__

(D107)


283-283: Missing type annotation for **kwargs

(ANN003)


331-377: Robust subscription management with proper error handling.

The subscribe/unsubscribe methods correctly implement log subscription for Transfer events with appropriate error handling, especially in the unsubscribe cleanup.

🧰 Tools
🪛 Ruff (0.11.9)

331-331: Missing type annotation for function argument websocket

(ANN001)


357-357: Missing type annotation for function argument websocket

(ANN001)


378-390: Clean implementation for single event collection.

The method efficiently captures the first log event using a state flag, which aligns well with the serverless execution model.

🧰 Tools
🪛 Ruff (0.11.9)

378-378: Missing type annotation for function argument websocket

(ANN001)


378-378: Dynamically typed expressions (typing.Any) are disallowed in listen_for_data

(ANN401)


391-419: Excellent resource management and error handling.

The method properly manages the WebSocket lifecycle with appropriate error handling and cleanup in the finally block.


420-471: Well-implemented timestamp-based latency calculation.

The method correctly calculates latency by fetching block timestamps via HTTP with comprehensive error handling. The approach of capturing current time before the HTTP request ensures accurate latency measurement.

Note: Creating a new ClientSession for each call is acceptable for serverless environments but could be optimized if this metric is collected frequently.


472-475: Appropriate placeholder implementation.

The method correctly documents that it's not used in the updated flow, serving only to satisfy the parent class interface.

@smypmsa smypmsa merged commit ebaa4cf into master Jun 11, 2025
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants