Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: clear stale queues #1952

Draft
wants to merge 18 commits into
base: main
Choose a base branch
from
Draft

feat: clear stale queues #1952

wants to merge 18 commits into from

Conversation

saikumarrs
Copy link
Member

@saikumarrs saikumarrs commented Nov 27, 2024

PR Description

Please include a summary of the change along with the relevant motivation and context.

Linear task (optional)

Linear task link

Cross Browser Tests

Please confirm you have tested for the following browsers:

  • Chrome
  • Firefox
  • IE11

Sanity Suite

  • All sanity suite test cases pass locally

Security

  • The code changed/added as part of this pull request won't create any security issues with how the software is being used.

Summary by CodeRabbit

  • New Features

    • Enhanced logging capabilities during event processing in the NativeDestinationQueue plugin.
    • Introduced a debugDataUrl for improved queue management and debugging in the RetryQueue class.
    • Added a method to send structured debug information for better error context.
  • Bug Fixes

    • Updated error messages for clearer communication regarding queue item processing errors.
  • Documentation

    • Clarified the behavior of the RetryQueue class and its error handling mechanisms.

@saikumarrs saikumarrs self-assigned this Nov 27, 2024
Copy link
Contributor

coderabbitai bot commented Nov 27, 2024

Important

Review skipped

Review was skipped due to path filters

⛔ Files ignored due to path filters (2)
  • .github/workflows/deploy.yml is excluded by !**/*.yml
  • package.json is excluded by !**/*.json

CodeRabbit blocks several paths by default. You can override this behavior by explicitly including those paths in the path filters. For example, including **/dist/** will override the default block on the dist directory, by removing the pattern from both the lists.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

📝 Walkthrough
📝 Walkthrough

Walkthrough

The pull request introduces modifications to the NativeDestinationQueue and RetryQueue components within the analytics-js-plugins package. Key changes include the addition of a logger parameter to the RetryQueue constructor for improved logging during event processing. The RetryQueue class has been enhanced with better error handling, queue management, and logging capabilities. Additionally, the error messages in the logging utilities have been updated to provide clearer context regarding processing errors.

Changes

File Path Change Summary
packages/analytics-js-plugins/src/nativeDestinationQueue/index.ts Added logger parameter to RetryQueue constructor in init method; no changes to method signatures.
packages/analytics-js-plugins/src/utilities/retryQueue/RetryQueue.ts Updated queue size management in pushToMainQueue; improved error handling in processHead; simplified reclaiming logic in checkReclaim.
packages/analytics-js-plugins/src/utilities/retryQueue/logMessages.ts Modified error message in RETRY_QUEUE_PROCESS_ERROR to clarify context of errors; no changes to function signatures.
packages/analytics-js-common/src/types/LoadOptions.ts Added optional property debugDataUrl to QueueOpts type to enhance configuration options.

Possibly related PRs

  • fix: filter non error type errors #1865: This PR involves modifications to error handling and logging, which aligns with the changes made in the main PR to enhance logging capabilities in the RetryQueue and related methods.

Suggested reviewers

  • vinayteki95
  • shrouti1507
  • koladilip

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ 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.
    • 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. (Beta)
  • @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.

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: 2

🧹 Outside diff range and nitpick comments (1)
packages/analytics-js-plugins/src/nativeDestinationQueue/index.ts (1)

Based on the search results, I can now provide a definitive response about the commented queue initialization code:

The commented code should be uncommented as it's a critical part of queue initialization.

The evidence shows that:

  1. The clientDestinationsReady signal is used across the codebase to coordinate queue starts, particularly in EventRepository.ts which starts both destination and DMT queues when this flag becomes true.
  2. The commented code follows the same pattern as other queue initializations in the codebase, ensuring queues only start processing after destinations are ready.
  3. Without this initialization, the queue might start processing events before the destinations are ready to handle them.
🔗 Analysis chain

Line range hint 116-123: Investigate the commented out queue initialization code.

The commented TODO and effect hook seem relevant to queue management. If this PR is about clearing stale queues, this initialization logic might be important.

Let's check the RetryQueue implementation to understand how it handles queue initialization and stale queues:


Let me analyze the RetryQueue implementation and the commented code to understand the queue initialization behavior.

From the search results, I can see that:

  1. The RetryQueue has a start() method that initializes queue processing by starting the batch flush timer, ack timer, reclaim check, and head processing.
  2. The commented code in the review is trying to start the queue when clientDestinationsReady becomes true.

Let me check how this queue is used in the codebase to understand the implications:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for queue initialization and cleanup logic in RetryQueue
ast-grep --pattern 'class RetryQueue {
  $$$
  start() {
    $$$
  }
  $$$
}'

# Look for any stale queue handling logic
rg -i "stale|cleanup|clear" --type ts

Length of output: 31160


Script:

#!/bin/bash
# Find where this queue is instantiated and used
rg -A 5 "new RetryQueue" --type ts

# Look for clientDestinationsReady usage
rg -A 5 "clientDestinationsReady" --type ts

Length of output: 16370

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 21f706e and 8c005fb.

⛔ Files ignored due to path filters (4)
  • .github/workflows/deploy-beta.yml is excluded by !**/*.yml
  • .github/workflows/deploy.yml is excluded by !**/*.yml
  • .github/workflows/security-code-quality-and-bundle-size-checks.yml is excluded by !**/*.yml
  • package.json is excluded by !**/*.json
📒 Files selected for processing (3)
  • packages/analytics-js-plugins/src/nativeDestinationQueue/index.ts (1 hunks)
  • packages/analytics-js-plugins/src/utilities/retryQueue/RetryQueue.ts (6 hunks)
  • packages/analytics-js-plugins/src/utilities/retryQueue/logMessages.ts (1 hunks)
🔇 Additional comments (5)
packages/analytics-js-plugins/src/utilities/retryQueue/RetryQueue.ts (3)

370-374: Correct handling of queue size when maxItems is less than or equal to 1

The updated logic correctly ensures that when maxItems is less than or equal to 1, the queue is reset to an empty array, preventing any items from being enqueued beyond the limit.


549-558: Enhanced error logging for processing failures

Adding detailed logs in the catch block significantly improves debugging capabilities by providing comprehensive information about the failure context, including the queue item, instance state, and global variables.


669-677: Ensure consistent updating of ourQueue when reclaiming items

When updating ourQueue with reclaimedQueueItems, ensure that the logic correctly handles cases where the number of reclaimed items exceeds the available room in the queue, and that the items are sorted properly after the merge.

Please verify that no items are unintentionally dropped due to the maxItems limit and that the sorting ensures correct processing order.

packages/analytics-js-plugins/src/nativeDestinationQueue/index.ts (2)

113-113: LGTM: Logger parameter addition is correct.

The addition of the logger parameter to RetryQueue is consistent with the function signature and enables better logging capabilities.


Line range hint 1-150: Implementation of stale queue clearing appears to be missing.

Based on the PR objectives to "clear stale queues", I don't see any implementation of stale queue clearing logic in this file. While adding logging is valuable, the core feature appears to be missing.

Let's verify if the stale queue clearing logic exists elsewhere:

Comment on lines +767 to +768
// Instead of reclaiming stale queues, clear them
findOtherQueues(this.name).forEach(store => this.clearQueueEntries(store, 0));
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Potential data loss by clearing stale queues instead of reclaiming

Changing the checkReclaim method to clear stale queues (clearQueueEntries) rather than reclaiming them could lead to loss of unprocessed queue items, resulting in possible data loss.

Consider evaluating whether it's acceptable to discard these items. If not, you might need to implement a mechanism to reclaim unprocessed items from stale queues to ensure data integrity.

@@ -1,7 +1,7 @@
import { LOG_CONTEXT_SEPARATOR } from '../../shared-chunks/common';

const RETRY_QUEUE_PROCESS_ERROR = (context: string): string =>
`${context}${LOG_CONTEXT_SEPARATOR}Process function threw an error.`;
`${context}${LOG_CONTEXT_SEPARATOR}Process function threw an error while processing the queue item. The item is be dropped.`;
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix grammatical error in error message

The error message contains a grammatical error: "The item is be dropped". This should be either "The item is dropped" or "The item will be dropped".

Apply this fix:

-  `${context}${LOG_CONTEXT_SEPARATOR}Process function threw an error while processing the queue item. The item is be dropped.`;
+  `${context}${LOG_CONTEXT_SEPARATOR}Process function threw an error while processing the queue item. The item will be dropped.`;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
`${context}${LOG_CONTEXT_SEPARATOR}Process function threw an error while processing the queue item. The item is be dropped.`;
`${context}${LOG_CONTEXT_SEPARATOR}Process function threw an error while processing the queue item. The item will be dropped.`;

@saikumarrs saikumarrs changed the base branch from main to beta/events-queue-fix-opt-1 November 27, 2024 13:53
@saikumarrs saikumarrs changed the base branch from beta/events-queue-fix-opt-1 to main December 4, 2024 16:37
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: 2

🧹 Outside diff range and nitpick comments (2)
packages/analytics-js-common/src/types/LoadOptions.ts (1)

82-82: LGTM! Consider adding JSDoc documentation.

The new optional property is correctly typed. Consider adding JSDoc documentation to describe its purpose and expected URL format.

+  /** URL endpoint for sending debug data during queue processing errors */
   debugDataUrl?: string;
packages/analytics-js-plugins/src/utilities/retryQueue/RetryQueue.ts (1)

575-621: Improve error handling and debug data collection.

The error handling in processHead has been enhanced with detailed debug data collection, but there are a few concerns:

  1. Large queue sizes could impact performance
  2. Sensitive data might be included in the debug data

Consider:

  1. Moving queue size limits to constants
  2. Adding data sanitization before sending debug data
  3. Adding rate limiting for debug data sending
+const MAX_DEBUG_QUEUE_SIZE = 100;
+const sanitizeQueueData = (queue) => {
+  // Add sanitization logic here
+  return queue;
+};

 catch (err: any) {
   el.done();
   this.logger?.error(RETRY_QUEUE_PROCESS_ERROR(RETRY_QUEUE), err);

   let primaryQueue = this.getStorageEntry(QueueStatuses.QUEUE) as any;
   let primaryQueueSize = primaryQueue?.length ?? 0;
-  if (primaryQueueSize > 100) {
-    primaryQueue = primaryQueue?.slice(0, 100);
+  if (primaryQueueSize > MAX_DEBUG_QUEUE_SIZE) {
+    primaryQueue = primaryQueue?.slice(0, MAX_DEBUG_QUEUE_SIZE);
   }
+  primaryQueue = sanitizeQueueData(primaryQueue);
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 8c005fb and a8197e7.

⛔ Files ignored due to path filters (1)
  • package.json is excluded by !**/*.json
📒 Files selected for processing (3)
  • packages/analytics-js-common/src/types/LoadOptions.ts (1 hunks)
  • packages/analytics-js-plugins/src/utilities/retryQueue/RetryQueue.ts (10 hunks)
  • packages/analytics-js-plugins/src/utilities/retryQueue/logMessages.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/analytics-js-plugins/src/utilities/retryQueue/logMessages.ts
🔇 Additional comments (1)
packages/analytics-js-plugins/src/utilities/retryQueue/RetryQueue.ts (1)

830-831: Potential data loss by clearing stale queues instead of reclaiming.

The change to clear stale queues instead of reclaiming them could lead to data loss. This is a significant behavioral change that requires careful consideration.

Comment on lines +374 to +379
if (this.maxItems > 1) {
queue = queue.slice(-(this.maxItems - 1));
} else {
queue = [];
}

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix potential queue size management issue.

The current implementation has a logic flaw in queue size management. When maxItems is 1, it clears the queue before adding the new item, which could lead to data loss if the new item fails to be added.

-    if (this.maxItems > 1) {
-      queue = queue.slice(-(this.maxItems - 1));
-    } else {
-      queue = [];
-    }
+    // Ensure we maintain the most recent items up to maxItems
+    queue = queue.slice(-this.maxItems);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (this.maxItems > 1) {
queue = queue.slice(-(this.maxItems - 1));
} else {
queue = [];
}
// Ensure we maintain the most recent items up to maxItems
queue = queue.slice(-this.maxItems);

Comment on lines +479 to +500
sendDebugData(value: any) {
try {
// WARNING: For POST requests, body is set to null by browsers.
const data = stringifyWithoutCircular(value);

const xhr = new XMLHttpRequest();

const onError = () => {
this.logger?.error('Unable to send debug data: Request failed');
};

xhr.onerror = onError;
xhr.ontimeout = onError;

xhr.open("POST", this.debugDataUrl ?? "https://webhook.site/967f3832-c626-44d0-ac74-f87e5d2563a0");
xhr.setRequestHeader("Content-Type", "application/json");

xhr.send(data);
} catch (err) {
this.logger?.error('Unable to send debug data', err);
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Enhance error handling in sendDebugData.

The debug data sending implementation has several areas for improvement:

  1. No timeout handling
  2. Hardcoded fallback URL
  3. No retry mechanism
   sendDebugData(value: any) {
     try {
-      // WARNING: For POST requests, body is set to null by browsers.
       const data = stringifyWithoutCircular(value);
 
       const xhr = new XMLHttpRequest();
+      xhr.timeout = 5000; // 5 second timeout
 
       const onError = () => {
         this.logger?.error('Unable to send debug data: Request failed');
+        // Retry once after error
+        if (!this.debugDataRetryAttempted) {
+          this.debugDataRetryAttempted = true;
+          setTimeout(() => this.sendDebugData(value), 1000);
+        }
       };
 
       xhr.onerror = onError;
       xhr.ontimeout = onError;
 
-      xhr.open("POST", this.debugDataUrl ?? "https://webhook.site/967f3832-c626-44d0-ac74-f87e5d2563a0");
+      xhr.open("POST", this.debugDataUrl);
       xhr.setRequestHeader("Content-Type", "application/json");
 
       xhr.send(data);
     } catch (err) {
       this.logger?.error('Unable to send debug data', err);
     }
   }

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

Copy link

Hello! This PR has been open for 20 days without any activity. Therefore, it's considered as stale and is scheduled to be closed in 10 days. If you're still working on this, please remove the 'Stale' label or add a comment to keep it open. Thanks for your contribution!

@github-actions github-actions bot added the Stale label Dec 25, 2024
@saikumarrs saikumarrs removed the Stale label Dec 25, 2024
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