Skip to content

Fix flakiness of prolog subscription queries#589

Merged
lucksus merged 14 commits intodevfrom
feature/fix-prolog-subscription-flaky
Apr 3, 2025
Merged

Fix flakiness of prolog subscription queries#589
lucksus merged 14 commits intodevfrom
feature/fix-prolog-subscription-flaky

Conversation

@lucksus
Copy link
Copy Markdown
Member

@lucksus lucksus commented Apr 3, 2025

Fix Flaky Behavior in Prolog Query Subscriptions

This PR addresses flaky behavior in the Prolog query subscription system by improving the synchronization between subscription setup and initial result delivery.

Key Changes

Rust Side (perspective_instance.rs)

  • Added a (100ms delayed) sending the initial subscription result and...

JavaScript Side (PerspectiveProxy.ts)

  • await initial result in client after subscription setup to ensure the subscription is fully set up before we continue
  • Refactored QuerySubscriptionProxy to properly handle initialization
  • Added an initialized Promise that resolves when the first subscription result is received
  • Modified subscribeInfer to wait for the subscription to be fully initialized before returning
  • Simplified subscription setup by creating the proxy with the initial result and waiting for initialization

Summary by CodeRabbit

  • New Features

    • Enhanced subscription flow ensures users receive an initial result promptly.
    • Improved asynchronous processing delivers faster and more reliable updates during subscriptions.
  • Bug Fixes

    • Updated test logic for better clarity and feedback during subscription updates.
  • Chores

    • Removed debug logging from subscription actions to streamline runtime visibility.
  • Documentation

    • Expanded method documentation to clarify subscription functionalities and initialization processes.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 3, 2025

Walkthrough

The pull request modifies the subscription initialization and handling across two modules. In the core module, a new private promise member #initialized is added to the QuerySubscriptionProxy class with an associated getter. The subscribeInfer method in PerspectiveProxy now waits for the promise resolution before returning the subscription. In the Rust executor module, the subscribe_and_query method in PerspectiveInstance spawns an asynchronous task that sends an initial result after a 100 ms delay, logs the action, and publishes the result in JSON format to a global pubsub topic. Additionally, minor changes are made to test logic and JSON files.

Changes

File(s) Change Summary
core/.../PerspectiveProxy.ts Introduced a private #initialized promise in QuerySubscriptionProxy, added a public getter, and updated subscribeInfer in PerspectiveProxy to await initialization.
rust-executor/.../perspective_instance.rs Added an asynchronous block in subscribe_and_query that spawns a task to delay 100 ms, then logs and publishes an initial JSON result to a global pubsub topic.
rust-executor/.../pubsub.rs Commented out a debug logging statement in subscribe_and_process and updated the import statement to remove the debug macro.
tests/js/bootstrapSeed.json Updated values in trustedAgents, knownLinkLanguages, directMessageLanguage, and agentLanguage keys.
tests/js/publishBootstrapSeed.json Completely replaced contents while retaining structure; internal implementation details modified.
tests/js/tests/prolog-and-literals.test.ts Modified waiting logic in tests for subscription updates, increasing attempts and reducing sleep interval, and added logging for attempts.

Sequence Diagram(s)

sequenceDiagram
  participant C as Client
  participant PP as PerspectiveProxy
  participant QSP as QuerySubscriptionProxy

  C->>PP: subscribeInfer(query)
  PP->>QSP: Instantiate & initiate async subscription
  QSP->>QSP: Wait for first result (resolve #initialized)
  QSP-->>PP: Promise resolved
  PP-->>C: Return subscription proxy
Loading
sequenceDiagram
  participant C as Client
  participant PI as PerspectiveInstance
  participant Task as Async Task
  participant PubSub as Global PubSub

  C->>PI: subscribe_and_query(query)
  PI->>PI: Insert subscription in map
  PI->>Task: Spawn async task with 100ms delay
  Task->>PubSub: Publish initial result (JSON format)
  Task-->>PI: Log the publishing action
  PI-->>C: Return subscription details
Loading

Poem

I'm a bunny coding in delight,
Hopping through promises day and night.
Async tasks skip with a gentle delay,
PubSub results come without dismay.
My little paws applaud each valid commit—
Hip-hop! Changes in code make my heart lit.
🐰🌟


📜 Recent review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between f2482d3 and d0bc3d8.

📒 Files selected for processing (2)
  • core/src/model/Ad4mModel.ts (3 hunks)
  • core/src/perspectives/PerspectiveProxy.ts (8 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Fleek - docsad4m
🔇 Additional comments (9)
core/src/perspectives/PerspectiveProxy.ts (6)

31-40: Documentation nicely reflects the new initialization behavior.

The updated docstring clearly explains the initialization process and the timeout behavior, which will help developers understand the subscription lifecycle.


65-66: Good addition of initialization Promise and timeout handling.

These new private members provide a robust way to track the subscription initialization state and prevent hanging if initialization fails.


81-100: Well-implemented initialization Promise with timeout safety.

The Promise implementation properly resolves when the first result is received and includes a timeout to prevent hanging subscriptions. The subscription setup is now wrapped within this Promise, which ensures proper sequencing.


122-133: Good addition of the initialized getter.

This getter provides a clean way for consumers to access the initialization state without exposing the private Promise.


199-202: Proper cleanup of initialization timeout.

The dispose method now correctly cleans up the initialization timeout, preventing potential memory leaks.


1128-1142: Key improvement: ensuring subscriptions are fully initialized before returning.

This is the core fix for the flakiness issue. By awaiting the initialization Promise before returning the subscription proxy, we ensure that the subscription is fully set up and has received its first result. This synchronization improvement should eliminate race conditions between subscription setup and result delivery.

core/src/model/Ad4mModel.ts (3)

1030-1039: Documentation improved for subscribe method.

The updated docstring clearly explains the subscription initialization process, aligning with the implementation changes in PerspectiveProxy.


1096-1103: Documentation improved for countSubscribe method.

The updated docstring consistently explains the initialization process, emphasizing that the subscription is guaranteed to be ready when the method returns.


1160-1167: Documentation improved for paginateSubscribe method.

The updated docstring follows the same pattern as the other subscription methods, maintaining consistency in explaining the initialization process.

✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 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 generate docstrings to generate docstrings for this 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.

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.

Copy link
Copy Markdown
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: 1

🧹 Nitpick comments (1)
core/src/perspectives/PerspectiveProxy.ts (1)

73-84: Improved subscription initialization with Promise pattern

This change encapsulates the subscription logic within a Promise that resolves when the first result is received, ensuring proper subscription initialization.

However, there's no error handling if the subscription setup fails.

Consider adding error handling by adding a timeout or rejection mechanism:

this.#initialized = new Promise<boolean>((resolve, reject) => {
    // Add timeout to prevent hanging promises
    const timeoutId = setTimeout(() => {
        reject(new Error('Subscription initialization timed out'));
    }, 30000); // 30 seconds timeout
            
    // Subscribe to query updates
    this.#unsubscribe = this.#client.subscribeToQueryUpdates(
        this.#subscriptionId,
        (result) => {
            clearTimeout(timeoutId);
            resolve(true);
            this.#latestResult = result;
            this.#notifyCallbacks(result);
        }
    );
});
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between f0396a8 and f2482d3.

📒 Files selected for processing (6)
  • core/src/perspectives/PerspectiveProxy.ts (4 hunks)
  • rust-executor/src/perspectives/perspective_instance.rs (1 hunks)
  • rust-executor/src/pubsub.rs (2 hunks)
  • tests/js/bootstrapSeed.json (1 hunks)
  • tests/js/publishBootstrapSeed.json (1 hunks)
  • tests/js/tests/prolog-and-literals.test.ts (2 hunks)
✅ Files skipped from review due to trivial changes (2)
  • rust-executor/src/pubsub.rs
  • tests/js/publishBootstrapSeed.json
🧰 Additional context used
🧬 Code Definitions (1)
tests/js/tests/prolog-and-literals.test.ts (2)
core/src/model/Ad4mModel.ts (1)
  • perspective (336-338)
core/src/perspectives/PerspectiveResolver.ts (1)
  • perspective (66-68)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Fleek - docsad4m
🔇 Additional comments (6)
rust-executor/src/perspectives/perspective_instance.rs (1)

2044-2064: Well-implemented improvement to subscription initialization

This change adds a 100ms delay before sending the initial subscription result, which helps synchronize query subscriptions and reduce flakiness as mentioned in the PR objectives. The implementation correctly:

  1. Clones necessary variables to avoid lifetime issues in the spawned task
  2. Uses a controlled delay with sleep to improve timing
  3. Creates and publishes the subscription filter properly
tests/js/bootstrapSeed.json (1)

1-1: Configuration updated with new keys

This update changes several values in the configuration file including:

  • trustedAgents
  • knownLinkLanguages
  • directMessageLanguage
  • agentLanguage

These changes appear to be part of the overall update to address the flakiness issues by ensuring consistent configuration across the codebase.

core/src/perspectives/PerspectiveProxy.ts (3)

59-59: New private field for tracking subscription initialization

Adding a Promise to track when the subscription is fully initialized is a good approach to help resolve the flakiness issues mentioned in the PR description.


108-110: New getter for accessing initialization status

This getter provides a clean way to access the initialization Promise, making it available for outside components like the subscribeInfer method to wait on.


1087-1101: Fixed race condition by waiting for initialization

This change is the key fix for the flakiness issue. By waiting for the initialized Promise to resolve before returning the subscription proxy, you ensure that the subscription is fully established and the initial result is available.

The approach aligns well with the Rust-side changes mentioned in the PR description, which add a 100ms delay before sending the initial result.

tests/js/tests/prolog-and-literals.test.ts (1)

1761-1774: Enhanced subscription waiting mechanism to reduce flakiness.

This modification improves the reliability of waiting for subscription updates by:

  1. Switching from a while loop to a more structured for loop
  2. Increasing the number of attempts from implicit 20 to explicit 50
  3. Reducing sleep interval from 500ms to 100ms (aligning with the 100ms delay added in the Rust code)
  4. Adding logging to provide better visibility during test execution
  5. Providing a more informative timeout error message

The total timeout period is now 5 seconds (down from 10), but with more frequent checking, which should work better with the changes made to the subscription initialization process.

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.

1 participant