Skip to content

feat(torii): deduped concurrent metadata updates - #3154

Merged
Larkooo merged 3 commits into
dojoengine:mainfrom
Larkooo:deduped-concurrent-metadata-updates
Apr 14, 2025
Merged

feat(torii): deduped concurrent metadata updates#3154
Larkooo merged 3 commits into
dojoengine:mainfrom
Larkooo:deduped-concurrent-metadata-updates

Conversation

@Larkooo

@Larkooo Larkooo commented Apr 10, 2025

Copy link
Copy Markdown
Collaborator

Summary by CodeRabbit

  • New Features
    • Streamlined NFT metadata updates with a unified data structure for improved clarity.
    • Introduced asynchronous processing for metadata tasks, reducing wait times and preventing duplicate updates.
    • Enhanced accessibility of methods for fetching token URI and metadata.
    • Added task management for NFT metadata updates to improve performance and responsiveness.

@coderabbitai

coderabbitai Bot commented Apr 10, 2025

Copy link
Copy Markdown
Contributor

Ohayo sensei! Below is the updated summary of the pull request:

Walkthrough

This pull request refines the NFT metadata update process. It introduces a new UpdateNftMetadata struct to encapsulate update data, makes methods like fetch_token_uri and fetch_token_metadata public, and renames update_nft_metadata to handle_update_nft_metadata with consolidated parameters. Additionally, the Executor struct is enhanced with asynchronous task management fields and logic to process metadata update tasks without duplicates.

Changes

File(s) Change Summary
crates/torii/.../erc.rs - Added new struct UpdateNftMetadata with token_id and metadata fields.
- Changed fetch_token_uri and fetch_token_metadata from private to public.
- Renamed update_nft_metadata to handle_update_nft_metadata, updating the parameter signature and internal logic to use the new struct and log updates.
crates/torii/.../mod.rs - Replaced UpdateNftMetadataQuery with UpdateNftMetadata in the Executor context.
- Added metadata_update_tasks (JoinSet) and metadata_update_tokens (HashSet) fields to the Executor struct.
- Updated the run and handle_query_message methods to spawn and manage async NFT metadata update tasks.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Executor
    participant Task
    participant DB
    participant Broker

    Client->>Executor: Request NFT metadata update
    Executor->>Executor: Check if token update already in progress
    Executor->>Task: Spawn handle_update_nft_metadata(UpdateNftMetadata)
    Task->>DB: Query/update NFT metadata in database
    DB-->>Task: Return updated metadata
    Task->>Broker: Publish updated token information
    Task-->>Executor: Return update result
Loading

Possibly related PRs

Suggested reviewers

  • glihm

📜 Recent review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro (Legacy)

📥 Commits

Reviewing files that changed from the base of the PR and between b847ea7 and d9d3f30.

📒 Files selected for processing (2)
  • crates/torii/sqlite/src/executor/erc.rs (5 hunks)
  • crates/torii/sqlite/src/executor/mod.rs (8 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • crates/torii/sqlite/src/executor/mod.rs
🧰 Additional context used
🧬 Code Graph Analysis (1)
crates/torii/sqlite/src/executor/erc.rs (1)
crates/torii/sqlite/src/utils.rs (3)
  • felt_to_sql_string (40-42)
  • fetch_content_from_ipfs (168-186)
  • sanitize_json_string (62-119)
🔇 Additional comments (4)
crates/torii/sqlite/src/executor/erc.rs (4)

40-44: Ohayo! Great encapsulation with the new UpdateNftMetadata struct.

This new struct nicely encapsulates the token_id and metadata fields, improving code organization and readability. This approach is better than passing these parameters separately.


315-389: The fetch_token_uri method is now public, nice work sensei!

Making this method public is a good change that enables reuse outside this module. The implementation is robust with multiple fallback mechanisms for different token URI formats.


391-397: Excellent refactoring of fetch_token_metadata!

The method now accepts a provider instead of token_uri and calls fetch_token_uri internally, which creates a more consistent API and reduces duplicate code. This approach is cleaner and follows better design principles.


419-437: Great work on the metadata update handler implementation!

The rename from update_nft_metadata to handle_update_nft_metadata better reflects its purpose, and using the new struct parameter simplifies the interface. The implementation properly logs successful updates and publishes events.


🪧 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.
    • Generate unit testing code for this file.
    • 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 generate unit testing code for this file.
    • @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 generate unit testing code.
    • @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.

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 resolve resolve all the CodeRabbit review comments.
  • @coderabbitai plan to trigger planning for file edits and PR creation.
  • @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.

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7d90c61 and 0a21ae2.

📒 Files selected for processing (2)
  • crates/torii/sqlite/src/executor/erc.rs (5 hunks)
  • crates/torii/sqlite/src/executor/mod.rs (7 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
crates/torii/sqlite/src/executor/mod.rs (2)
crates/torii/sqlite/src/utils.rs (2)
  • felt_and_u256_to_sql_string (44-46)
  • felt_to_sql_string (40-42)
crates/torii/sqlite/src/executor/erc.rs (3)
  • handle_update_nft_metadata (440-459)
  • token_id (78-78)
  • token_id (113-113)
🔇 Additional comments (12)
crates/torii/sqlite/src/executor/mod.rs (7)

10-10: Ohayo! Updated imports for the new struct.

You've properly updated the imports to include the new UpdateNftMetadata struct that replaces the previous UpdateNftMetadataQuery type. This aligns well with the refactoring approach, sensei!


150-153: Nice addition of task management fields!

Ohayo! These new fields are excellent additions to support concurrent processing of metadata updates:

  • metadata_update_tasks tracks the asynchronous tasks for metadata updates
  • metadata_update_tokens maintains a set of token IDs currently being processed, which enables deduplication

This approach will prevent redundant work when multiple requests come in for the same token, sensei!


267-268: Proper initialization of new fields, sensei!

The new fields are correctly initialized in the new method, maintaining consistency with other collection initializations in this struct.


297-300: Good handling of task results in the run loop!

Ohayo! This branch in the select macro correctly processes completed metadata update tasks by:

  1. Awaiting the next completed task
  2. Unwrapping both the outer and inner Result (with ??)
  3. Passing the result to handle_update_nft_metadata

This ensures metadata updates are processed as soon as they complete, sensei!


792-795: Excellent deduplication implementation!

The token ID check prevents duplicate processing of the same token, which is the core improvement mentioned in the PR title. This efficiently prevents wasted work when multiple requests come in for the same token.


797-819: Well-structured async task for metadata updates!

Ohayo! The task spawning implementation is excellent:

  1. Properly acquires a semaphore permit to limit concurrent tasks
  2. Fetches token URI and metadata asynchronously
  3. Constructs the UpdateNftMetadata with the results
  4. Properly releases the permit with drop(permit)

This approach keeps the main executor loop responsive while metadata fetching happens in the background, sensei!


845-848: Good cleanup of pending tasks during execution!

This loop ensures that any pending metadata update tasks are completed and processed before the transaction is committed, maintaining data consistency, sensei!

crates/torii/sqlite/src/executor/erc.rs (5)

40-44: Well-designed struct for metadata updates!

Ohayo, sensei! The new UpdateNftMetadata struct is well-designed and encapsulates exactly what's needed for a metadata update operation. This makes the code more maintainable and the parameter passing more explicit.


338-338: Good move making fetch_token_uri public!

Making this method public allows it to be called from the spawned tasks in mod.rs, supporting the new asynchronous approach. This is a sensible change that improves code organization, sensei!


414-414: Good move making fetch_token_metadata public!

Ohayo! Similar to fetch_token_uri, making this method public supports the new asynchronous processing approach. The change is consistent with the overall refactoring strategy, sensei!


440-443: Great method signature simplification!

Renaming to handle_update_nft_metadata and using the new struct as a parameter makes the method signature cleaner and more maintainable. This is a good example of the Single Responsibility Principle in action, sensei!


445-456: Clean implementation using the new struct!

Ohayo! The implementation has been nicely updated to use the new UpdateNftMetadata struct:

  1. Properly binds the metadata and token_id fields for the update query
  2. Handles the optional result correctly
  3. Logs success and publishes the update when a token is found

This maintains all the functionality while making the code cleaner, sensei!

Comment on lines +788 to +819

let metadata_semaphore = self.metadata_semaphore.clone();
let provider = self.provider.clone();

let token_id = felt_and_u256_to_sql_string(&update_metadata.contract_address, &update_metadata.token_id);
if self.metadata_update_tokens.contains(&token_id) {
return Ok(());
}

self.metadata_update_tasks.spawn(async move {
let permit = metadata_semaphore.acquire().await.unwrap();

let token_uri = Self::fetch_token_uri(
&provider,
update_metadata.contract_address,
update_metadata.token_id,
)
.await?;
let metadata = Self::fetch_token_metadata(
update_metadata.contract_address,
update_metadata.token_id,
&token_uri,
)
.await?;


drop(permit);
Ok(UpdateNftMetadata {
token_id,
metadata,
})
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Consider cleaning up the tokens set after processing

Ohayo, sensei! While you're adding tokens to the metadata_update_tokens set, I don't see where they're being removed once processing is complete. This could potentially lead to a memory leak if tokens are never removed from the set.

Consider adding code to remove the token ID from the set after processing:

 pub async fn handle_update_nft_metadata(
     &mut self,
     update_metadata: UpdateNftMetadata,
 ) -> Result<()> {
+    // Remove token from the set of tokens being processed
+    self.metadata_update_tokens.remove(&update_metadata.token_id);
     
     // Update metadata in database
     let token = sqlx::query_as::<_, Token>("UPDATE tokens SET metadata = ? WHERE id = ? RETURNING *")

Committable suggestion skipped: line range outside the PR's diff.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (1)
crates/torii/sqlite/src/executor/mod.rs (1)

794-817: Consider cleaning up the tokens set after processing

Ohayo, sensei! While you're adding tokens to the metadata_update_tokens set, I don't see where they're being removed once processing is complete. This could potentially lead to a memory leak if tokens are never removed from the set.

Consider adding code to remove the token ID from the set after processing:

 pub async fn handle_update_nft_metadata(
     &mut self,
     update_metadata: UpdateNftMetadata,
 ) -> Result<()> {
+    // Remove token from the set of tokens being processed
+    self.metadata_update_tokens.remove(&update_metadata.token_id);
     
     // Update metadata in database
     let token = sqlx::query_as::<_, Token>("UPDATE tokens SET metadata = ? WHERE id = ? RETURNING *")
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro (Legacy)

📥 Commits

Reviewing files that changed from the base of the PR and between 0a21ae2 and b847ea7.

📒 Files selected for processing (2)
  • crates/torii/sqlite/src/executor/erc.rs (5 hunks)
  • crates/torii/sqlite/src/executor/mod.rs (8 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
crates/torii/sqlite/src/executor/mod.rs (2)
crates/torii/sqlite/src/executor/erc.rs (6)
  • sqlx (287-287)
  • sqlx (424-424)
  • handle_update_nft_metadata (419-438)
  • fetch_token_metadata (391-417)
  • token_id (78-78)
  • token_id (113-113)
crates/torii/sqlite/src/utils.rs (2)
  • felt_and_u256_to_sql_string (44-46)
  • felt_to_sql_string (40-42)
🪛 GitHub Actions: ci
crates/torii/sqlite/src/executor/mod.rs

[error] 14-14: Rust formatting check failed. Please run 'rustfmt' to format the code.


[error] 27-27: Rust formatting check failed. Please run 'rustfmt' to format the code.

crates/torii/sqlite/src/executor/erc.rs

[error] 18-18: Rust formatting check failed. Please run 'rustfmt' to format the code.


[error] 421-421: Rust formatting check failed. Please run 'rustfmt' to format the code.

🔇 Additional comments (9)
crates/torii/sqlite/src/executor/mod.rs (5)

10-10: Updated imports to include the new UpdateNftMetadata struct.

Ohayo, sensei! The import statement now includes the new UpdateNftMetadata struct from the erc module, which will be used for handling NFT metadata updates with the new deduplication mechanism.


151-153: Great addition of fields for async task management!

Ohayo, sensei! These new fields are excellent additions:

  • metadata_update_tasks helps manage asynchronous metadata update operations
  • metadata_update_tokens tracks which tokens are already being processed to prevent duplicate updates

This aligns perfectly with the PR objective of deduplicating concurrent metadata updates.


267-268: New fields properly initialized in the constructor.

Ohayo! These new fields are correctly initialized in the new method, with metadata_update_tasks as a new JoinSet and metadata_update_tokens as an empty HashSet. Good work, sensei!


297-300: Excellent addition to process metadata update tasks.

Ohayo, sensei! This new branch in the run method elegantly handles results from metadata_update_tasks by invoking handle_update_nft_metadata. This ensures that asynchronous metadata updates are properly processed in the main event loop.


843-846: Great handling of pending metadata update tasks.

Ohayo, sensei! The execute method now correctly processes any pending metadata update tasks, ensuring all updates are completed before finishing execution. This is good practice to ensure no tasks are left hanging.

crates/torii/sqlite/src/executor/erc.rs (4)

40-44: Well-designed new struct for metadata updates.

Ohayo, sensei! The new UpdateNftMetadata struct is cleanly designed with the necessary fields:

  • token_id: A string identifier for the token
  • metadata: The token's metadata as a string

This struct encapsulates the data needed for updating NFT metadata and supports the deduplication mechanism in the main executor.


315-315: Good exposure of methods as public APIs.

Ohayo, sensei! Making these methods public is appropriate as they're now used outside this module. This change enhances the API's flexibility and supports the new asynchronous metadata update workflow.

Also applies to: 391-391, 419-419


396-397: Excellent refactoring of token metadata fetching.

Ohayo! Having fetch_token_metadata call fetch_token_uri internally is a great refactoring that:

  1. Streamlines the code flow
  2. Reduces duplication
  3. Makes the dependency between these methods explicit

This is clean, maintainable code, sensei!


419-438: Great simplification of the update method.

Ohayo, sensei! The handle_update_nft_metadata method now accepts a single UpdateNftMetadata struct parameter instead of multiple separate parameters. This is a good API design that:

  1. Simplifies the method signature
  2. Makes it clear what data is needed for updates
  3. Makes the code more maintainable

The implementation is also clean, updating the database, logging the result, and publishing the updated token.

🧰 Tools
🪛 GitHub Actions: ci

[error] 421-421: Rust formatting check failed. Please run 'rustfmt' to format the code.

use sqlx::{FromRow, Pool, Sqlite, Transaction as SqlxTransaction};
use starknet::core::types::requests::CallRequest;
use starknet::core::types::{BlockId, BlockTag, Felt, FunctionCall};
use starknet::core::utils::{get_selector_from_name, parse_cairo_short_string};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

❓ Verification inconclusive

Fix formatting issues flagged by CI.

Ohayo, sensei! The CI pipeline has flagged formatting issues on lines 14 and 27. Please run rustfmt to fix these issues.

Also applies to: 27-27


🏁 Script executed:

#!/bin/bash
# Run rustfmt to fix formatting issues
rustfmt crates/torii/sqlite/src/executor/mod.rs

Length of output: 147


Ohayo, sensei!

The CI pipeline flagged formatting issues on lines 14 and 27 of crates/torii/sqlite/src/executor/mod.rs. However, when attempting to run rustfmt, the command wasn’t found in the environment. It appears that rustfmt isn’t installed or isn’t accessible at the moment.

To address this, please:

  • Ensure that rustfmt is installed (for example, by running rustup component add rustfmt).
  • Re-run the formatting command on the file:
    rustfmt crates/torii/sqlite/src/executor/mod.rs
    

Once rustfmt is properly installed, its execution should auto-format the file and clear the CI formatting issues.

🧰 Tools
🪛 GitHub Actions: ci

[error] 14-14: Rust formatting check failed. Please run 'rustfmt' to format the code.

Comment thread crates/torii/sqlite/src/executor/erc.rs
@Larkooo
Larkooo enabled auto-merge (squash) April 11, 2025 02:40
@Larkooo
Larkooo merged commit be6d051 into dojoengine:main Apr 14, 2025
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