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

fix: too fast polling #4007

Merged

Conversation

maxinteger
Copy link
Contributor

@maxinteger maxinteger commented Nov 26, 2024

COMPLETES [SPARK-586223](issue: https://jira-eng-gpk2.cisco.com/jira/browse/SPARK-586223)

This pull request addresses

Handle slow_down error message from server

by making the following changes

  • skip 1 interval in polling after the server respond with 'slow_down'
  • prevent emitting events from previous polling sessions
  • refactored timeout logic

Change Type

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update
  • Tooling change
  • Internal code refactor

The following scenarios were tested

  • Added 2 new unite tests to cover the new functionalities
  • fixed the existing unit tests
  • manual tested with Cantina PR #7020

I certified that

  • I have read and followed contributing guidelines

  • I discussed changes with code owners prior to submitting this pull request

  • I have not skipped any automated checks

  • All existing and new tests passed

  • I have updated the documentation accordingly


Make sure to have followed the contributing guidelines before submitting.

Summary by CodeRabbit

Summary by CodeRabbit

  • New Features

    • Enhanced event-driven communication for authorization events with the introduction of the Events constant.
    • Improved polling mechanism for user authorization, allowing dynamic scheduling and better error handling.
  • Bug Fixes

    • Resolved issues with CSRF token handling and OAuth parameter processing.
    • Improved cancellation logic for polling requests to prevent concurrent requests.
  • Tests

    • Expanded test coverage for authorization logic, including CSRF token validation and polling behavior.
    • Added tests for error handling during authorization code exchanges.

@maxinteger maxinteger requested a review from a team as a code owner November 26, 2024 15:47
Copy link

coderabbitai bot commented Nov 26, 2024

Walkthrough

The changes in this pull request focus on the AuthorizationBrowserFirstParty class within the authorization.js file. Key modifications include the introduction of new properties for managing polling and event handling, such as eventEmitter, pollingExpirationTimer, and pollingId. The polling mechanism has been refactored from using setInterval to setTimeout, allowing for more flexible scheduling. Additionally, the test suite for the authorization logic has been enhanced with new test cases and improved assertions to ensure comprehensive coverage of various scenarios and error handling.

Changes

File Change Summary
packages/@webex/plugin-authorization-browser-first-party/src/authorization.js - Added properties: eventEmitter, pollingExpirationTimer, pollingId, currentPollingId
- Renamed pollingRequest to pollingTimer
- Refactored polling logic from setInterval to setTimeout
- Updated methods for better error handling and event emission.
packages/@webex/plugin-authorization-browser-first-party/test/unit/spec/authorization.js - Enhanced test coverage with new test cases and refined assertions
- Updated makeWebex function for mock instance creation
- Improved tests for CSRF token handling and OAuth parameter processing
- Clarified polling logic tests for QR code login.
packages/@webex/plugin-authorization-browser-first-party/src/index.js - Updated export statement to include Events alongside the default export from ./authorization.

Possibly related PRs

  • feat(automotive): qr code login flow for automotive app  #3974: The changes in this PR directly relate to the AuthorizationBrowserFirstParty class in authorization.js, specifically adding properties and methods for QR code login, which aligns with the modifications made in the main PR regarding polling and event handling for authorization events.

Suggested reviewers

  • chburket
  • mickelr

Poem

🐰 In the realm of code, so bright and new,
A rabbit hops with changes due.
Polling timers dance and play,
EventEmitters lead the way.
With tests that shine, and errors tamed,
Our authorization's now acclaimed! 🌟

Warning

There were issues while running some tools. Please review the errors and either fix the tool’s configuration or disable the tool if it’s a critical failure.

🔧 eslint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

warning [email protected]: This version is no longer supported. Please see https://eslint.org/version-support for other options.
warning eslint > @humanwhocodes/[email protected]: Use @eslint/config-array instead
warning eslint > @humanwhocodes/config-array > @humanwhocodes/[email protected]: Use @eslint/object-schema instead
warning eslint > file-entry-cache > flat-cache > [email protected]: Rimraf versions prior to v4 are no longer supported
warning eslint > file-entry-cache > flat-cache > rimraf > [email protected]: Glob versions prior to v9 are no longer supported
warning eslint > file-entry-cache > flat-cache > rimraf > glob > [email protected]: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.
warning eslint-import-resolver-typescript > [email protected]: Glob versions prior to v9 are no longer supported
warning [email protected]: Glob versions prior to v9 are no longer supported
warning intern > [email protected]: Glob versions prior to v9 are no longer supported
warning intern > glob > [email protected]: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.
warning jasmine > [email protected]: Glob versions prior to v9 are no longer supported
warning jest > @jest/core > jest-config > [email protected]: Glob versions prior to v9 are no longer supported
warning jest > @jest/core > @jest/reporters > [email protected]: Glob versions prior to v9 are no longer supported
warning jest > @jest/core > jest-runtime > [email protected]: Glob versions prior to v9 are no longer supported
warning jest > @jest/core > @jest/transform > babel-plugin-istanbul > test-exclude > [email protected]: Glob versions prior to v9 are no longer supported
warning mocha > [email protected]: Glob versions prior to v9 are no longer supported
warning mocha > glob > [email protected]: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.
warning [email protected]: 16.1.1
warning wd > archiver > [email protected]: Glob versions prior to v9 are no longer supported
warning wd > [email protected]: You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other.

(For a CapTP with native promises, see @endo/eventual-send and @endo/captp)
warning wd > [email protected]: request has been deprecated, see request/request#3142
warning wd > archiver > archiver-utils > [email protected]: Glob versions prior to v9 are no longer supported
warning wd > request > [email protected]: Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.
warning wd > request > [email protected]: this library is no longer supported
warning @babel/cli > [email protected]: Glob versions prior to v9 are no longer supported
warning @babel/[email protected]: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-async-generator-functions instead.
warning @babel/[email protected]: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-class-properties instead.
warning @babel/[email protected]: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-export-namespace-from instead.
warning @babel/[email protected]: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-nullish-coalescing-operator instead.
warning @babel/[email protected]: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-object-rest-spread instead.
warning @babel/[email protected]: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-optional-chaining instead.
warning @babel/[email protected]: 🚨 This package has been deprecated in favor of separate inclusion of a polyfill and regenerator-runtime (when needed). See the @babel/polyfill docs (https://babeljs.io/docs/en/babel-polyfill) for more information.
warning @babel/polyfill > [email protected]: core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.
warning @babel/runtime-corejs2 > [email protected]: core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.
warning babel-plugin-lodash > [email protected]: Glob versions prior to v9 are no longer supported
warning workspace-aggregator-bc35f9e7-2e9f-469f-aee2-f10a2488583d > [email protected]: This version is no longer supported. Please see https://eslint.org/version-support for other options.
warning workspace-aggregator-bc35f9e7-2e9f-469f-aee2-f10a2488583d > [email protected]: Glob versions prior to v9 are no longer supported
warning workspace-aggregator-bc35f9e7-2e9f-469f-aee2-f10a2488583d > [email protected]: 16.1.1
warning workspace-aggregator-bc35f9e7-2e9f-469f-aee2-f10a2488583d > @babel/[email protected]: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-async-generator-functions instead.
warning workspace-aggregator-bc35f9e7-2e9f-469f-aee2-f10a2488583d > @babel/[email protected]: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-class-properties instead.
warning workspace-aggregator-bc35f9e7-2e9f-469f-aee2-f10a2488583d > @babel/[email protected]: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-export-namespace-from instead.
warning workspace-aggregator-bc35f9e7-2e9f-469f-aee2-f10a2488583d > @babel/[email protected]: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-nullish-coalescing-operator instead.
warning workspace-aggregator-bc35f9e7-2e9f-469f-aee2-f10a2488583d > @babel/[email protected]: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-object-rest-spread instead.
warning workspace-aggregator-bc35f9e7-2e9f-469f-aee2-f10a2488583d > @babel/[email protected]: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-optional-chaining instead.
warning workspace-aggregator-bc35f9e7-2e9f-469f-aee2-f10a2488583d > @babel/[email protected]: 🚨 This package has been deprecated in favor of separate inclusion of a polyfill and regenerator-runtime (when needed). See the @babel/polyfill docs (https://babeljs.io/docs/en/babel-polyfill) for more information.
error [email protected]: The engine "node" is incompatible with this module. Expected version "^14 || ^16 || ^17 || ^18 || ^19". Got "22.9.0"
error Found incompatible module.


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 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.

@maxinteger maxinteger force-pushed the fix/SPARK-586223-too-fast-auth-polling branch from 0dd0d89 to 46623f8 Compare November 26, 2024 15:48
@maxinteger maxinteger added the validated If the pull request is validated for automation. label Nov 26, 2024
Copy link

This pull request is automatically being deployed by Amplify Hosting (learn more).

Access this pull request here: https://pr-4007.d3m3l2kee0btzx.amplifyapp.com

Copy link

@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: 3

🧹 Outside diff range and nitpick comments (4)
packages/@webex/plugin-authorization-browser-first-party/test/unit/spec/authorization.js (4)

464-469: Include 'expires_in' in 'sampleData' for consistency

The sampleData object lacks the expires_in field, which is used in other tests for timing purposes. Including it will make the test data consistent and ensure accurate timing in the test.

Apply this diff to include expires_in:

            const sampleData = {
              device_code: 'test123',
+             expires_in: 300,
              user_code: '421175',
              verification_uri: 'http://example.com',
              verification_uri_complete: 'http://example.com',
              interval: 2,
            };

501-506: Include 'expires_in' in 'sampleData' for consistency

The sampleData object lacks the expires_in field, which is used in other tests for timing purposes. Including it will make the test data consistent and ensure accurate timing in the test.

Apply this diff to include expires_in:

            const sampleData = {
              device_code: 'test123',
+             expires_in: 300,
              user_code: '421175',
              verification_uri: 'http://example.com',
              verification_uri_complete: 'http://example.com',
              interval: 2,
            };

611-611: Remove commented-out code

There's a commented-out call to await clock.runAllAsync(). Please remove it if it's no longer needed to keep the code clean.

Apply this diff to remove the commented code:

-            //await clock.runAllAsync()

715-715: Inconsistent error message—use 'authorization_pending'

The error message in the rejected promises is 'authorizationPending', but according to the OAuth 2.0 Device Flow specification, it should be 'authorization_pending'. Ensure consistency in error messages.

Apply this diff to correct the error messages:

// At line 715
-              .rejects({statusCode: 428, body: {message: 'authorizationPending'}});
+              .rejects({statusCode: 428, body: {message: 'authorization_pending'}});

// At line 751
-            webex.request.rejects({statusCode: 428, body: {message: 'authorizationPending'}});
+            webex.request.rejects({statusCode: 428, body: {message: 'authorization_pending'}});

Also applies to: 751-751

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between c4ba3e5 and 46623f8.

📒 Files selected for processing (2)
  • packages/@webex/plugin-authorization-browser-first-party/src/authorization.js (8 hunks)
  • packages/@webex/plugin-authorization-browser-first-party/test/unit/spec/authorization.js (13 hunks)
🧰 Additional context used
🪛 Biome (1.9.4)
packages/@webex/plugin-authorization-browser-first-party/src/authorization.js

[error] 361-361: Illegal return statement outside of a function

(parse)


[error] 437-437: The assignment should not be in an expression.

The use of assignments in expressions is confusing.
Expressions are often considered as side-effect free.

(lint/suspicious/noAssignInExpressions)


[error] 448-461: This block statement doesn't serve any purpose and can be safely removed.

Standalone block statements without any block-level declarations are redundant in JavaScript and can be removed to simplify the code.

(lint/complexity/noUselessLoneBlockStatements)

🔇 Additional comments (2)
packages/@webex/plugin-authorization-browser-first-party/src/authorization.js (2)

448-461: 🛠️ Refactor suggestion

Remove redundant block statement in cancelQRCodePolling method

There's an unnecessary block statement in the cancelQRCodePolling method that doesn't serve any purpose and can be safely removed to simplify the code.

Apply this diff to remove the redundant block:

 cancelQRCodePolling(withCancelEvent = true) {
-  {
     if (this.pollingTimer && withCancelEvent) {
       this.eventEmitter.emit('qRCodeLogin', {
         eventType: 'pollingCanceled',
       });
     }

     this.currentPollingId = null;

     clearTimeout(this.pollingExpirationTimer);
     this.pollingExpirationTimer = null;
     clearTimeout(this.pollingTimer);
     this.pollingTimer = null;
-  }
 }

Ensure that all braces are correctly matched and that the method does not contain unnecessary blocks that could confuse readers or cause unintended behaviors.

Likely invalid or redundant comment.

🧰 Tools
🪛 Biome (1.9.4)

[error] 448-461: This block statement doesn't serve any purpose and can be safely removed.

Standalone block statements without any block-level declarations are redundant in JavaScript and can be removed to simplify the code.

(lint/complexity/noUselessLoneBlockStatements)


356-361: ⚠️ Potential issue

Fix 'return' statement outside of function scope

The return statement at line 361 is outside the function scope, which causes a syntax error: "Illegal return statement outside of a function." This prevents the code from executing correctly.

Apply this diff to ensure the return statement is within the function scope:

 if (this.pollingTimer) {
   this.eventEmitter.emit('qRCodeLogin', {
     eventType: 'authorizationFailure',
     data: {message: 'There is already a polling request'},
   });
-  return;
+    return;
 }

Make sure the indentation reflects that the return statement is inside the if block and the function _startQRCodePolling.

Likely invalid or redundant comment.

🧰 Tools
🪛 Biome (1.9.4)

[error] 361-361: Illegal return statement outside of a function

(parse)

Copy link

@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

🧹 Outside diff range and nitpick comments (2)
packages/@webex/plugin-authorization-browser-first-party/src/authorization.js (2)

363-364: Consider using a named constant for the default expiration.

The default value of 300 seconds should be defined as a named constant at the class level for better maintainability.

+ static DEFAULT_EXPIRATION_SECONDS = 300;
+
- const {device_code: deviceCode, expires_in: expiresIn = 300} = options;
+ const {device_code: deviceCode, expires_in: expiresIn = this.DEFAULT_EXPIRATION_SECONDS} = options;

447-459: Consider extracting timer cleanup logic.

While the implementation is correct, the timer cleanup logic could be more maintainable if extracted into a separate method.

+ _cleanupTimers() {
+   clearTimeout(this.pollingExpirationTimer);
+   this.pollingExpirationTimer = null;
+   clearTimeout(this.pollingTimer);
+   this.pollingTimer = null;
+ }
+
  cancelQRCodePolling(withCancelEvent = true) {
    if (this.pollingTimer && withCancelEvent) {
      this.eventEmitter.emit('qRCodeLogin', {
        eventType: 'pollingCanceled',
      });
    }

    this.currentPollingId = null;
-   clearTimeout(this.pollingExpirationTimer);
-   this.pollingExpirationTimer = null;
-   clearTimeout(this.pollingTimer);
-   this.pollingTimer = null;
+   this._cleanupTimers();
  }
🧰 Tools
🪛 Biome (1.9.4)

[error] 447-460: This block statement doesn't serve any purpose and can be safely removed.

Standalone block statements without any block-level declarations are redundant in JavaScript and can be removed to simplify the code.

(lint/complexity/noUselessLoneBlockStatements)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 46623f8 and 92f1630.

📒 Files selected for processing (1)
  • packages/@webex/plugin-authorization-browser-first-party/src/authorization.js (7 hunks)
🧰 Additional context used
🪛 Biome (1.9.4)
packages/@webex/plugin-authorization-browser-first-party/src/authorization.js

[error] 360-360: Illegal return statement outside of a function

(parse)


[error] 436-436: The assignment should not be in an expression.

The use of assignments in expressions is confusing.
Expressions are often considered as side-effect free.

(lint/suspicious/noAssignInExpressions)


[error] 447-460: This block statement doesn't serve any purpose and can be safely removed.

Standalone block statements without any block-level declarations are redundant in JavaScript and can be removed to simplify the code.

(lint/complexity/noUselessLoneBlockStatements)

🔇 Additional comments (5)
packages/@webex/plugin-authorization-browser-first-party/src/authorization.js (5)

70-112: LGTM! Well-structured property declarations.

The new properties are well-documented with JSDoc comments and follow a consistent naming convention. The eventEmitter and polling-related properties provide a clear separation of concerns for managing the polling state.


Line range hint 295-326: LGTM! Robust initialization with proper error handling.

The changes properly prevent concurrent polling requests and maintain consistent event emission patterns. The success path appropriately transitions to polling state.


408-414: LGTM! Proper handling of slow_down error.

The implementation correctly handles the slow_down error by doubling the interval and continuing polling, which aligns with common rate-limiting best practices.


435-437: 🛠️ Refactor suggestion

Refactor assignment in arrow function.

The assignment within the arrow function expression can be confusing and is flagged by static analysis. Let's make it more explicit.

- const schedulePolling = (interval) =>
-   (this.pollingTimer = setTimeout(polling, interval * 1000));
+ const schedulePolling = (interval) => {
+   this.pollingTimer = setTimeout(polling, interval * 1000);
+ };

Likely invalid or redundant comment.

🧰 Tools
🪛 Biome (1.9.4)

[error] 436-436: The assignment should not be in an expression.

The use of assignments in expressions is confusing.
Expressions are often considered as side-effect free.

(lint/suspicious/noAssignInExpressions)


Line range hint 295-459: Verify the polling interval behavior in production.

The changes look good and address the PR objectives. However, since this is a critical authentication component, it would be prudent to verify the polling behavior in production, especially:

  1. The handling of slow_down errors
  2. The prevention of stale events from previous polling sessions
  3. The cleanup of timers on cancellation
✅ Verification successful

Based on the search results, I can see that the polling interval behavior and slow_down handling are properly implemented in the codebase. Let me verify the specific aspects mentioned in the review comment with additional context.


Based on the search results, I can see that the code has proper implementation and test coverage for all the key polling behaviors:

  1. Timer cleanup and stale event prevention:
  • Uses currentPollingId to prevent stale events
  • Properly cleans up timers in cancelQRCodePolling
  • Checks for existing polling before starting new one
  1. Slow down error handling:
  • Correctly handles 400 status with 'slow_down' message
  • Doubles the interval when slow_down is received
  • Has test coverage: "should skip a interval when server ask for slow_down"
  1. Polling interval behavior:
  • Properly respects polling intervals
  • Has test coverage for interval behavior
  • Handles expiration timeouts correctly

The implementation is robust and well-tested. No production verification needed.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for any existing issues or discussions about polling intervals
# and rate limiting in the codebase

# Search for related comments about polling intervals
rg -i "polling.*interval|slow.*down" --type js

# Search for rate limiting related code
ast-grep --pattern 'slow_down'

Length of output: 132670


Script:

#!/bin/bash
# Search for polling timer cleanup and stale event prevention
rg -A 5 "pollingTimer|currentPollingId" --type js

# Search for slow_down error handling implementation
rg -A 5 "slow_down.*statusCode.*400" --type js

# Search for test cases related to polling behavior
rg -A 10 "should.*polling" --type js

Length of output: 143498

🧰 Tools
🪛 Biome (1.9.4)

[error] 436-436: The assignment should not be in an expression.

The use of assignments in expressions is confusing.
Expressions are often considered as side-effect free.

(lint/suspicious/noAssignInExpressions)

Copy link
Contributor

@sreenara sreenara left a comment

Choose a reason for hiding this comment

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

LGTM. Just one question.

@@ -446,46 +446,46 @@ describe('plugin-authorization-browser-first-party', () => {
describe('#initQRCodeLogin()', () => {
it('should prevent concurrent request if there is already a polling request', async () => {
Copy link
Contributor

Choose a reason for hiding this comment

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

question. Shouldn't the initQRCodeLogin return immediately if there is already a polling request? How does the code reach the catch block and emit the getUserCodeFailure event?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Previously we hade 2 ways to report errors, 1) reject the promise from initQRCodeLogin and 2) emit error form _startQRCodePolling.

Then we unified the two and now we handle all errors with events and initQRCodeLogin does not return with promise anymore

- skip 1 interval in polling after the server respond with 'slow_down'
- prevent emitting events from previous polling sessions
- refactored timeout logic

issue: https://jira-eng-gpk2.cisco.com/jira/browse/SPARK-586223
- Removed unused import
@maxinteger maxinteger force-pushed the fix/SPARK-586223-too-fast-auth-polling branch from 92f1630 to 53045fd Compare November 28, 2024 14:02
Copy link

@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

🧹 Outside diff range and nitpick comments (2)
packages/@webex/plugin-authorization-browser-first-party/test/unit/spec/authorization.js (2)

611-611: Remove commented code

The commented line //await clock.runAllAsync() is unnecessary and should be removed.


781-785: Maintain consistent whitespace

There are inconsistent blank lines around assertions. Consider maintaining a single blank line between logical groups of assertions for better readability.

Apply this diff:

 webex.authorization._startQRCodePolling(options);
 assert.isDefined(webex.authorization.pollingTimer);
-
 webex.authorization.cancelQRCodePolling();
 assert.isNull(webex.authorization.pollingTimer);
-
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 92f1630 and 53045fd.

📒 Files selected for processing (2)
  • packages/@webex/plugin-authorization-browser-first-party/src/authorization.js (7 hunks)
  • packages/@webex/plugin-authorization-browser-first-party/test/unit/spec/authorization.js (13 hunks)
🧰 Additional context used
🪛 Biome (1.9.4)
packages/@webex/plugin-authorization-browser-first-party/src/authorization.js

[error] 360-360: Illegal return statement outside of a function

(parse)


[error] 436-436: The assignment should not be in an expression.

The use of assignments in expressions is confusing.
Expressions are often considered as side-effect free.

(lint/suspicious/noAssignInExpressions)


[error] 447-460: This block statement doesn't serve any purpose and can be safely removed.

Standalone block statements without any block-level declarations are redundant in JavaScript and can be removed to simplify the code.

(lint/complexity/noUselessLoneBlockStatements)

🔇 Additional comments (8)
packages/@webex/plugin-authorization-browser-first-party/src/authorization.js (5)

70-112: LGTM! Well-structured property declarations

The new properties are well-documented and form a coherent set for managing polling state and events.


Line range hint 295-326: LGTM! Good concurrent polling prevention

The check for existing polling requests prevents resource waste and provides clear feedback through events.


Line range hint 374-433: LGTM! Robust polling implementation with proper error handling

The implementation effectively handles various scenarios:

  • Prevents stale events using pollingId tracking
  • Properly handles 'slow_down' responses by doubling the interval
  • Maintains polling for pending authorizations
🧰 Tools
🪛 Biome (1.9.4)

[error] 436-436: The assignment should not be in an expression.

The use of assignments in expressions is confusing.
Expressions are often considered as side-effect free.

(lint/suspicious/noAssignInExpressions)


447-459: LGTM! Complete cleanup of polling resources

The cancellation implementation:

  • Properly cleans up all timers
  • Prevents stale events by resetting currentPollingId
  • Provides flexibility with the withCancelEvent parameter
🧰 Tools
🪛 Biome (1.9.4)

[error] 447-460: This block statement doesn't serve any purpose and can be safely removed.

Standalone block statements without any block-level declarations are redundant in JavaScript and can be removed to simplify the code.

(lint/complexity/noUselessLoneBlockStatements)


435-437: 🛠️ Refactor suggestion

Refactor the arrow function to avoid assignment in expression

The current implementation assigns within an expression, which can be confusing and is flagged by static analysis.

Apply this diff to improve clarity:

-const schedulePolling = (interval) =>
-  (this.pollingTimer = setTimeout(polling, interval * 1000));
+const schedulePolling = (interval) => {
+  this.pollingTimer = setTimeout(polling, interval * 1000);
+};

Likely invalid or redundant comment.

🧰 Tools
🪛 Biome (1.9.4)

[error] 436-436: The assignment should not be in an expression.

The use of assignments in expressions is confusing.
Expressions are often considered as side-effect free.

(lint/suspicious/noAssignInExpressions)

packages/@webex/plugin-authorization-browser-first-party/test/unit/spec/authorization.js (3)

664-693: Well-implemented test for slow_down handling

This test case effectively verifies that the polling mechanism respects the server's slow_down message by skipping one interval. This directly addresses the PR objective of fixing too fast polling.


695-736: Good test coverage for polling state management

This test case thoroughly verifies that responses from previous polling sessions are properly ignored, preventing race conditions and ensuring clean state management.


273-279: 🛠️ Refactor suggestion

Use consistent assertion style

The test uses expect while the rest of the test file uses assert. For consistency, use assert from chai.

Apply this diff to maintain consistency:

-          expect(err?.message).toBe('Cannot convert object to primitive value');
+          assert.equal(err?.message, 'Cannot convert object to primitive value');

Likely invalid or redundant comment.

this.pollingExpirationTimer = setTimeout(() => {
this.cancelQRCodePolling(false);
this.eventEmitter.emit('qRCodeLogin', {
eventType: 'authorizationFailure',
Copy link
Collaborator

Choose a reason for hiding this comment

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

the emitted event types should probably be in some enum or some other type so that client using this API can easily know what are all possible events they can get without reading the implementation.

- added exported Events object for better consumer side API
Copy link

@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

🧹 Outside diff range and nitpick comments (1)
packages/@webex/plugin-authorization-browser-first-party/src/authorization.js (1)

28-33: Consider defining event types as an enumeration

Following up on the previous review comment, consider defining all possible event types (getUserCodeSuccess, getUserCodeFailure, etc.) in the Events constant to make the API more discoverable.

 export const Events = {
   /**
    * QR code login events
    */
-  qRCodeLogin: 'qRCodeLogin',
+  qRCodeLogin: {
+    name: 'qRCodeLogin',
+    types: {
+      GET_USER_CODE_SUCCESS: 'getUserCodeSuccess',
+      GET_USER_CODE_FAILURE: 'getUserCodeFailure',
+      AUTHORIZATION_SUCCESS: 'authorizationSuccess',
+      AUTHORIZATION_FAILURE: 'authorizationFailure',
+      AUTHORIZATION_PENDING: 'authorizationPending',
+      POLLING_CANCELED: 'pollingCanceled'
+    }
+  }
 };
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 53045fd and 6b0a33e.

📒 Files selected for processing (2)
  • packages/@webex/plugin-authorization-browser-first-party/src/authorization.js (7 hunks)
  • packages/@webex/plugin-authorization-browser-first-party/src/index.js (1 hunks)
🧰 Additional context used
🪛 Biome (1.9.4)
packages/@webex/plugin-authorization-browser-first-party/src/authorization.js

[error] 362-362: Illegal return statement outside of a function

(parse)


[error] 370-370: Illegal return statement outside of a function

(parse)


[error] 446-446: The assignment should not be in an expression.

The use of assignments in expressions is confusing.
Expressions are often considered as side-effect free.

(lint/suspicious/noAssignInExpressions)


[error] 457-470: This block statement doesn't serve any purpose and can be safely removed.

Standalone block statements without any block-level declarations are redundant in JavaScript and can be removed to simplify the code.

(lint/complexity/noUselessLoneBlockStatements)

🔇 Additional comments (7)
packages/@webex/plugin-authorization-browser-first-party/src/index.js (2)

17-17: LGTM! Clean addition of Events export.

The addition of the Events export aligns with the PR's objective to improve polling session management and event handling.


17-17: Verify Events constant usage.

Let's verify how the Events constant is being used in relation to the polling mechanism.

✅ Verification successful

Events constant is correctly used with polling mechanism

The Events constant is properly defined and used in the codebase. It defines a single event qRCodeLogin which is emitted during various polling states including:

  • When handling slow_down responses from the server
  • During polling initialization
  • For authorization success/failure states
  • When polling is cancelled
  • When authorization is pending

The polling mechanism correctly uses the Events constant to communicate its state changes, and the slow_down error handling is properly implemented with the event system.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check the Events constant definition and its usage in polling-related code

# Check Events definition and usage in authorization.js
echo "Checking Events definition and usage in authorization.js:"
rg -A 5 "Events.*=.*{" packages/@webex/plugin-authorization-browser-first-party/src/authorization.js

# Check for polling-related usage of Events
echo "Checking polling-related usage of Events:"
rg -A 10 "slow_down.*Events|Events.*slow_down" packages/@webex/plugin-authorization-browser-first-party/

Length of output: 515


Script:

#!/bin/bash
# Let's try a different approach to check Events definition and usage

# First, let's check the Events constant definition
echo "Checking Events constant definition:"
rg "export const Events" packages/@webex/plugin-authorization-browser-first-party/src/

# Then, check any Events object definition
echo -e "\nChecking Events object definition:"
rg "const Events = {" packages/@webex/plugin-authorization-browser-first-party/src/

# Check all usages of Events in the codebase
echo -e "\nChecking all Events usages:"
rg "Events\." packages/@webex/plugin-authorization-browser-first-party/src/

# Check files importing Events
echo -e "\nChecking Events imports:"
rg "import.*Events" packages/@webex/plugin-authorization-browser-first-party/src/

Length of output: 2146


Script:

#!/bin/bash
# Let's check the Events definition and see if there are any polling-related events

echo "Checking Events definition content:"
rg -A 10 "export const Events = {" packages/@webex/plugin-authorization-browser-first-party/src/authorization.js

# Also check for any polling-related code
echo -e "\nChecking for polling-related code:"
rg -B 2 -A 5 "poll" packages/@webex/plugin-authorization-browser-first-party/src/authorization.js

Length of output: 4672


Script:

#!/bin/bash
# Let's check the actual Events constant definition with a simpler pattern

echo "Checking Events constant definition:"
rg -B 1 -A 5 "^export const Events" packages/@webex/plugin-authorization-browser-first-party/src/authorization.js

# Also check if there are any other files using the slow_down error handling
echo -e "\nChecking for slow_down handling in other files:"
rg "slow_down" packages/@webex/plugin-authorization-browser-first-party/src/

Length of output: 836

packages/@webex/plugin-authorization-browser-first-party/src/authorization.js (5)

80-122: LGTM! Well-documented properties

The new properties are well-documented with JSDoc comments and have clear purposes.


Line range hint 305-346: LGTM! Robust initialization with proper guards

The implementation properly prevents concurrent polling requests and consistently handles success/failure cases.


418-423: LGTM! Good implementation of backoff strategy

The implementation properly handles the slow_down message by doubling the polling interval.


457-469: LGTM! Thorough cleanup of polling resources

The implementation properly cleans up all timers and prevents stale requests through pollingId reset.

🧰 Tools
🪛 Biome (1.9.4)

[error] 457-470: This block statement doesn't serve any purpose and can be safely removed.

Standalone block statements without any block-level declarations are redundant in JavaScript and can be removed to simplify the code.

(lint/complexity/noUselessLoneBlockStatements)


445-447: 🛠️ Refactor suggestion

Avoid assignment within expression

Following up on the previous review comment, the assignment within the arrow function expression should be refactored for better readability.

-const schedulePolling = (interval) =>
-  (this.pollingTimer = setTimeout(polling, interval * 1000));
+const schedulePolling = (interval) => {
+  this.pollingTimer = setTimeout(polling, interval * 1000);
+};
🧰 Tools
🪛 Biome (1.9.4)

[error] 446-446: The assignment should not be in an expression.

The use of assignments in expressions is confusing.
Expressions are often considered as side-effect free.

(lint/suspicious/noAssignInExpressions)

@maxinteger maxinteger merged commit 99c21e8 into webex:next Nov 29, 2024
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
validated If the pull request is validated for automation.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants