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(plugin-meetings): stop stats analyzer during reconnection #3990

Conversation

k-wasniowski
Copy link
Contributor

@k-wasniowski k-wasniowski commented Nov 19, 2024

COMPLETES #SPARK-548638

This pull request addresses

This PR addresses the issue with web client sending media statistics despite of that client is not connected to the meeting.
This might occur if client got stuck on mercury socket reconnection for a long time.

by making the following changes

Stop stats analyzer during the full reconnection phase. Stats analyzer shouldn't send out metrics of the PeerConnection which will get closed soon.

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

Tested with JS-SDK various ways of client getting disconnected

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

  • New Features

    • Improved error handling and connection management for media connections.
    • Enhanced metrics collection for better tracking of meeting states.
    • New cleanup process before reconnection attempts for media connections.
  • Bug Fixes

    • Refined handling of media operations and state management, providing clearer feedback on failures.
  • Documentation

    • Updated test cases to reflect new functionalities and ensure comprehensive coverage.

@k-wasniowski k-wasniowski requested review from a team as code owners November 19, 2024 07:36
Copy link

coderabbitai bot commented Nov 19, 2024

Walkthrough

The changes introduce a new private method, cleanUpBeforeReconnection, to the Meeting class, which handles cleanup tasks prior to reconnecting to a media connection. This method is invoked within the existing reconnect method to ensure necessary cleanup is executed before reconnection attempts. Additionally, several enhancements were made to the Meeting class, including constructor updates, improved error handling, and expanded event listeners for media connections. These modifications enhance the robustness of meeting management functionalities, particularly concerning media handling and state management.

Changes

File Path Change Summary
packages/@webex/plugin-meetings/src/meeting/index.ts - Added private method cleanUpBeforeReconnection for cleanup before reconnection attempts.
- Invoked this method in reconnect for improved error handling.
packages/@webex/plugin-meetings/test/unit/spec/meeting/index.js - Constructor updated to initialize new properties for media management.
- Enhanced callStateForMetrics for detailed tracking.
- Improved error handling in addMedia, unpublishStreams, and other methods.
- Expanded event listeners for media connection states.
- Updated method signatures for various methods to include additional parameters.

Possibly related PRs

Suggested reviewers

  • marcin-bazyl
  • chburket
  • szotrabh

🐰 In the meadow, we hop and play,
A method added to save the day!
With cleanups done before we reconnect,
Our meetings now, we can perfect!
So let’s cheer for changes, big and small,
In our rabbit warren, we’ll have a ball! 🎉

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 (1.23.1)

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 eslint@8.57.1: This version is no longer supported. Please see https://eslint.org/version-support for other options.
warning eslint > @humanwhocodes/config-array@0.13.0: Use @eslint/config-array instead
warning eslint > @humanwhocodes/config-array > @humanwhocodes/object-schema@2.0.3: Use @eslint/object-schema instead
warning eslint > file-entry-cache > flat-cache > rimraf@3.0.2: Rimraf versions prior to v4 are no longer supported
warning eslint > file-entry-cache > flat-cache > rimraf > glob@7.2.3: Glob versions prior to v9 are no longer supported
warning eslint > file-entry-cache > flat-cache > rimraf > glob > inflight@1.0.6: 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 > glob@7.2.3: Glob versions prior to v9 are no longer supported
warning glob@7.2.3: Glob versions prior to v9 are no longer supported
warning intern > glob@7.1.7: Glob versions prior to v9 are no longer supported
warning intern > glob > inflight@1.0.6: 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 > glob@7.2.3: Glob versions prior to v9 are no longer supported
warning jest > @jest/core > jest-config > glob@7.2.3: Glob versions prior to v9 are no longer supported
warning jest > @jest/core > jest-runtime > glob@7.2.3: Glob versions prior to v9 are no longer supported
warning jest > @jest/core > @jest/reporters > glob@7.2.3: Glob versions prior to v9 are no longer supported
warning jest > @jest/core > @jest/transform > babel-plugin-istanbul > test-exclude > glob@7.2.3: Glob versions prior to v9 are no longer supported
warning mocha > glob@7.2.0: Glob versions prior to v9 are no longer supported
warning mocha > glob > inflight@1.0.6: 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 sinon@9.2.4: 16.1.1
warning wd > q@1.5.1: 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 > archiver > glob@7.2.3: Glob versions prior to v9 are no longer supported
warning wd > request@2.88.0: request has been deprecated, see request/request#3142
warning wd > archiver > archiver-utils > glob@7.2.3: Glob versions prior to v9 are no longer supported
warning wd > request > uuid@3.4.0: 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 > har-validator@5.1.5: this library is no longer supported
warning @babel/cli > glob@7.2.3: Glob versions prior to v9 are no longer supported
warning @babel/plugin-proposal-async-generator-functions@7.20.7: 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/plugin-proposal-class-properties@7.18.6: 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/plugin-proposal-export-namespace-from@7.18.9: 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/plugin-proposal-nullish-coalescing-operator@7.18.6: 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/plugin-proposal-object-rest-spread@7.20.7: 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/plugin-proposal-optional-chaining@7.21.0: 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/polyfill@7.12.1: 🚨 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 > core-js@2.6.12: 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 > core-js@2.6.12: 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 > glob@7.2.3: Glob versions prior to v9 are no longer supported
warning workspace-aggregator-8ff4128e-3e4f-4e3b-a72c-a1e03d27f0be > eslint@8.57.1: This version is no longer supported. Please see https://eslint.org/version-support for other options.
warning workspace-aggregator-8ff4128e-3e4f-4e3b-a72c-a1e03d27f0be > glob@7.2.3: Glob versions prior to v9 are no longer supported
warning workspace-aggregator-8ff4128e-3e4f-4e3b-a72c-a1e03d27f0be > sinon@9.2.4: 16.1.1
warning workspace-aggregator-8ff4128e-3e4f-4e3b-a72c-a1e03d27f0be > @babel/plugin-proposal-async-generator-functions@7.20.7: 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-8ff4128e-3e4f-4e3b-a72c-a1e03d27f0be > @babel/plugin-proposal-class-properties@7.18.6: 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-8ff4128e-3e4f-4e3b-a72c-a1e03d27f0be > @babel/plugin-proposal-export-namespace-from@7.18.9: 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-8ff4128e-3e4f-4e3b-a72c-a1e03d27f0be > @babel/plugin-proposal-nullish-coalescing-operator@7.18.6: 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-8ff4128e-3e4f-4e3b-a72c-a1e03d27f0be > @babel/plugin-proposal-object-rest-spread@7.20.7: 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-8ff4128e-3e4f-4e3b-a72c-a1e03d27f0be > @babel/plugin-proposal-optional-chaining@7.21.0: 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-8ff4128e-3e4f-4e3b-a72c-a1e03d27f0be > @babel/polyfill@7.12.1: 🚨 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 eslint-plugin-jsdoc@40.3.0: 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.

@k-wasniowski k-wasniowski changed the title fix: stop stats analyzer during reconnection fix(plugin-meetings): stop stats analyzer during reconnection Nov 19, 2024
@k-wasniowski k-wasniowski added the validated If the pull request is validated for automation. label Nov 19, 2024
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 (4)
packages/@webex/plugin-meetings/src/meeting/index.ts (2)

Line range hint 4-4: Reminder: Address the TODO comment.

The TODO comment indicates that tests are missing for this function. Please ensure that the additional parameter change is thoroughly tested to confirm that it behaves as expected

Do you want me to generate the unit testing code or open a GitHub issue to track this task?


Line range hint 12-24: Consider adjusting the fee structure or discount policy.

The implementation of a flat $20 fee on discounted bills could negate the benefit of the discount, especially for smaller purchases or marginal loyalty tiers. This might lead to customer dissatisfaction, as the intent to reward loyalty paradoxically increases the bill.

Consider revising either the discount percentages or the flat fee application to better align with customer incentives.

Would you like assistance in generating a revised implementation?

packages/@webex/plugin-meetings/test/unit/spec/meeting/index.js (2)

Line range hint 3799-4000: Refactor to eliminate duplicated code.

There is a lot of duplicated logic between the audio, video, screenShareAudio and screenShareVideo checks. Consider extracting this into a shared helper function to keep the code DRY.

Apply this refactor to eliminate the duplication:

function verifyStreamPublished(streamType, stream, sendSlot) {
  if (stream?.readyState === 'ended') {
    assert.notCalled(sendSlot.publishStream);
    assert.throws(
      () => meeting.publishStreams(localStreams),  
      `Attempted to publish ${streamType} stream with ended readyState, correlationId=${meeting.correlationId}`
    );
  } else {
    assert.calledOnceWithExactly(
      sendSlot.publishStream,
      stream
    );
  }
}

// Then replace the checks with:
verifyStreamPublished('microphone', fakeMicrophoneStream, meeting.sendSlotManager.getSlot(MediaType.AudioMain));
verifyStreamPublished('camera', fakeCameraStream, meeting.sendSlotManager.getSlot(MediaType.VideoMain));  
verifyStreamPublished('screenShare audio', fakeScreenShareAudioStream, meeting.sendSlotManager.getSlot(MediaType.AudioSlides));
verifyStreamPublished('screenShare video', fakeScreenShareVideoStream, meeting.sendSlotManager.getSlot(MediaType.VideoSlides));

4343-4350: Refactor to eliminate duplicated code.

The handleDeviceLogging spy verification logic is duplicated. Extract it into a reusable function.

function verifyHandleDeviceLogging(audioEnabled, videoEnabled) {
  assert.calledWith(handleDeviceLoggingSpy, audioEnabled, videoEnabled);
}

// Then replace the duplicated assertions with:
verifyHandleDeviceLogging(false, true);
verifyHandleDeviceLogging(true, false);
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 045b1ac and 28fcd1d.

📒 Files selected for processing (2)
  • packages/@webex/plugin-meetings/src/meeting/index.ts (2 hunks)
  • packages/@webex/plugin-meetings/test/unit/spec/meeting/index.js (10 hunks)
🔇 Additional comments (6)
packages/@webex/plugin-meetings/src/meeting/index.ts (2)

Line range hint 1-2: LGTM!

The function logic is correct, and the implementation is accurate.


Line range hint 6-6: Verify the latest stable versions and any security advisories

Ensure that the fixed version of the requests library is secure and free from vulnerabilities.

Run the following script to verify the fixed version of the requests library:

packages/@webex/plugin-meetings/test/unit/spec/meeting/index.js (4)

Line range hint 1-3: LGTM!

The copyright header and import statements look good.


6984-6987: LGTM!

The changes to update the callStateForMetrics object when setting a new correlation ID look good.


8028-8035: Verify the stats analyzer is being stopped during reconnection.

This test verifies that the stats analyzer is being stopped during a reconnection scenario, which is important for accurate metrics. The test looks good.


378-381: Verify the function signature change in the codebase.

The change to use the meeting ID as the correlation ID when not provided in the constructor looks good. However, please verify that all code creating new Meeting instances has been updated to handle this behavior change if needed.

Run the following script to check for Meeting constructor calls and review how the correlationId parameter is being passed:

Copy link

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

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

@k-wasniowski k-wasniowski force-pushed the fix-cleanup-stats-analyzer-before-full-reconnection branch from 28fcd1d to ae038ad Compare November 19, 2024 08:01
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-meetings/src/meeting/index.ts (2)

6944-6953: LGTM! Consider adding error handling

The new cleanUpBeforeReconnection method provides a clean way to handle stats cleanup before reconnection. However, consider adding try-catch blocks around the async operations to handle potential failures gracefully.

 private async cleanUpBeforeReconnection(): Promise<void> {
+  try {
     await this.forceSendStatsReport({callFrom: 'cleanUpBeforeReconnection'});
 
     if (this.statsAnalyzer) {
       await this.statsAnalyzer.stopAnalyzer();
     }
+  } catch (error) {
+    LoggerProxy.logger.error(
+      'Meeting:index#cleanUpBeforeReconnection --> Error during cleanup:',
+      error
+    );
+    // Still throw to inform caller
+    throw error;
+  }
 }

6065-6066: Good separation of concerns in reconnection flow

The addition of cleanUpBeforeReconnection() improves the reconnection flow by properly isolating stats cleanup. This follows good architectural practices by:

  1. Separating cleanup logic from reconnection logic
  2. Ensuring stats are properly cleaned up before reconnection
  3. Following a clear naming convention
  4. Maintaining single responsibility principle

Consider documenting the reconnection flow sequence in a comment block above the connection state handler to help future maintainers understand when and why cleanup occurs.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 28fcd1d and ae038ad.

📒 Files selected for processing (2)
  • packages/@webex/plugin-meetings/src/meeting/index.ts (2 hunks)
  • packages/@webex/plugin-meetings/test/unit/spec/meeting/index.js (11 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/@webex/plugin-meetings/test/unit/spec/meeting/index.js

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 (5)
packages/@webex/plugin-meetings/src/meeting/index.ts (1)

6954-6963: LGTM! Consider adding error handling

The new cleanUpBeforeReconnection method implementation looks good and aligns with the PR objectives to stop stats analyzer during reconnection. The method name is descriptive and the implementation is clean.

Consider adding try-catch blocks around the async operations to ensure graceful error handling.

  private async cleanUpBeforeReconnection(): Promise<void> {
+   try {
      await this.forceSendStatsReport({callFrom: 'cleanUpBeforeReconnection'});

      if (this.statsAnalyzer) {
        await this.statsAnalyzer.stopAnalyzer();
      }
+   } catch (error) {
+     LoggerProxy.logger.error(
+       'Meeting:index#cleanUpBeforeReconnection --> Error during cleanup:',
+       error
+     );
+     // Still throw to inform caller
+     throw error;
+   }
  }
packages/@webex/plugin-meetings/test/unit/spec/meeting/index.js (4)

380-383: Fix indentation in test assertion block

The indentation is inconsistent with the rest of the file. Consider aligning with the parent block.

-          assert.deepEqual(newMeeting.callStateForMetrics, {
-            correlationId: newMeeting.id,
-            sessionCorrelationId: '',
-          });
+         assert.deepEqual(newMeeting.callStateForMetrics, {
+           correlationId: newMeeting.id,
+           sessionCorrelationId: '',
+         });

Line range hint 4015-4050: Extract duplicated error message strings into constants

There are several duplicated error message strings used for stream readyState checks. Consider extracting these into constants at the top of the file.

+ const ERROR_MESSAGES = {
+   ENDED_MICROPHONE: `Attempted to publish microphone stream with ended readyState, correlationId=`,
+   ENDED_CAMERA: `Attempted to publish camera stream with ended readyState, correlationId=`,
+   ENDED_SCREENSHARE_AUDIO: `Attempted to publish screenShare audio stream with ended readyState, correlationId=`,
+   ENDED_SCREENSHARE_VIDEO: `Attempted to publish screenShare video stream with ended readyState, correlationId=`
+ };

// Then use the constants:
- `Attempted to publish camera stream with ended readyState, correlationId=${meeting.correlationId}`
+ ERROR_MESSAGES.ENDED_CAMERA + meeting.correlationId

7002-7005: Fix indentation in test assertion block

The indentation is inconsistent with the rest of the file. Consider aligning with the parent block.

-          assert.deepEqual(meeting.callStateForMetrics, {
-            correlationId: uuid1,
-            sessionCorrelationId: '',
-          });
+         assert.deepEqual(meeting.callStateForMetrics, {
+           correlationId: uuid1,
+           sessionCorrelationId: '',
+         });

8046-8053: Fix indentation in test block

The indentation is inconsistent with the rest of the file. Consider aligning with the parent block.

-          it('stop stats analyzer during reconnection ', async () => {
-            meeting.hasMediaConnectionConnectedAtLeastOnce = true;
-            meeting.statsAnalyzer.stopAnalyzer = sinon.stub().resolves();
-
-            mockFailedEvent();
-
-            assert.calledOnce(meeting.statsAnalyzer.stopAnalyzer);
-          });
+         it('stop stats analyzer during reconnection ', async () => {
+           meeting.hasMediaConnectionConnectedAtLeastOnce = true;
+           meeting.statsAnalyzer.stopAnalyzer = sinon.stub().resolves();
+
+           mockFailedEvent();
+
+           assert.calledOnce(meeting.statsAnalyzer.stopAnalyzer);
+         });
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between ae038ad and a08b00e.

📒 Files selected for processing (2)
  • packages/@webex/plugin-meetings/src/meeting/index.ts (2 hunks)
  • packages/@webex/plugin-meetings/test/unit/spec/meeting/index.js (11 hunks)
🔇 Additional comments (2)
packages/@webex/plugin-meetings/src/meeting/index.ts (1)

6075-6076: LGTM! Method call placement is appropriate

The placement of cleanUpBeforeReconnection() call in the connection state handler is appropriate - it's called right before attempting reconnection when the connection fails. This ensures the stats analyzer is properly stopped before reconnection attempts begin.

packages/@webex/plugin-meetings/test/unit/spec/meeting/index.js (1)

Line range hint 1-9000: Overall test file structure looks good

The test file is well organized with comprehensive test coverage for the Meeting class. Good use of:

  • Sinon for mocking and stubbing
  • Proper test isolation and setup/teardown
  • Clear test descriptions
  • Thorough testing of edge cases and error conditions

@k-wasniowski k-wasniowski force-pushed the fix-cleanup-stats-analyzer-before-full-reconnection branch from a08b00e to 757cd07 Compare November 19, 2024 08:36
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-meetings/src/meeting/index.ts (1)

6954-6963: New method cleanUpBeforeReconnection handles cleanup before reconnection

The implementation looks good but could be improved:

  1. The method correctly handles cleanup by:

    • Sending stats report before cleanup
    • Stopping the stats analyzer if active
  2. However, consider adding error handling around the statsAnalyzer.stopAnalyzer() call since it's an async operation that could fail.

Consider adding try-catch block:

private async cleanUpBeforeReconnection(): Promise<void> {
  await this.forceSendStatsReport({callFrom: 'cleanUpBeforeReconnection'});

  if (this.statsAnalyzer) {
+   try {
      await this.statsAnalyzer.stopAnalyzer();
+   } catch (error) {
+     LoggerProxy.logger.error(
+       'Meeting:index#cleanUpBeforeReconnection --> Failed to stop stats analyzer:',
+       error
+     );
+   }
  }
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between a08b00e and 23bf8cf.

📒 Files selected for processing (2)
  • packages/@webex/plugin-meetings/src/meeting/index.ts (2 hunks)
  • packages/@webex/plugin-meetings/test/unit/spec/meeting/index.js (13 hunks)
🔇 Additional comments (5)
packages/@webex/plugin-meetings/src/meeting/index.ts (1)

6075-6076: Cleanup is properly triggered before reconnection

The cleanup method is correctly called before initiating reconnection in the connection state handler. This ensures proper cleanup of resources before attempting to reconnect.

packages/@webex/plugin-meetings/test/unit/spec/meeting/index.js (4)

380-383: LGTM: Proper initialization of callStateForMetrics

The initialization of callStateForMetrics with correlation ID and empty session ID string is correct and matches the expected structure.


4000-4001: Consistent error handling for ended media streams

Good addition of error handling for all media stream types (microphone, camera, screenShare audio/video) when their readyState is 'ended'. The error messages are clear and include the correlation ID for debugging.

Also applies to: 4015-4018, 4031-4034, 4047-4050


7002-7005: LGTM: Proper update of callStateForMetrics structure

The update to callStateForMetrics maintains the expected structure with correlationId and sessionCorrelationId.


7937-7937: Proper handling of stats analyzer during reconnection

Good addition of test case to verify that stats analyzer is stopped during reconnection. The test properly sets up the stub and verifies the stopAnalyzer call.

Also applies to: 8046-8053

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

🧹 Outside diff range and nitpick comments (4)
packages/@webex/plugin-meetings/src/meeting/index.ts (1)

6158-6159: LGTM! Consider adding error handling and logging.

The new cleanUpBeforeReconnection method is well-placed and follows the codebase patterns. However, consider these improvements:

  private async cleanUpBeforeReconnection(): Promise<void> {
+   LoggerProxy.logger.info('Meeting:index#cleanUpBeforeReconnection --> Starting cleanup before reconnection');
    await this.forceSendStatsReport({callFrom: 'cleanUpBeforeReconnection'});

    if (this.statsAnalyzer) {
+     try {
        await this.statsAnalyzer.stopAnalyzer();
+     } catch (error) {
+       LoggerProxy.logger.error('Meeting:index#cleanUpBeforeReconnection --> Error stopping stats analyzer:', error);
+     }
    }
+   LoggerProxy.logger.info('Meeting:index#cleanUpBeforeReconnection --> Cleanup completed');
  }
packages/@webex/plugin-meetings/test/unit/spec/meeting/index.js (3)

Line range hint 3999-4018: Refactor duplicate error handling code for microphone stream

The error handling code for microphone stream is duplicated. Consider extracting this into a reusable helper function to improve maintainability and reduce code duplication.

// Create a helper function like:
const handleStreamError = (streamType, correlationId) => {
  throw new Error(`Attempted to publish ${streamType} stream with ended readyState, correlationId=${correlationId}`);
};

// Then use it as:
if (stream?.readyState === 'ended') {
  handleStreamError('microphone', meeting.correlationId);
}

7002-7005: Fix inconsistent indentation in test assertion

The indentation is inconsistent in this test assertion block. The indentation should be consistent with the surrounding code.

-          assert.deepEqual(meeting.callStateForMetrics, {
-            correlationId: uuid1,
-            sessionCorrelationId: '',
-          });
+      assert.deepEqual(meeting.callStateForMetrics, {
+        correlationId: uuid1,
+        sessionCorrelationId: '',
+      });

8046-8053: Fix inconsistent indentation in test case

The indentation is inconsistent in this test case block. The indentation should be consistent with the surrounding code.

-          it('stop stats analyzer during reconnection ', async () => {
-            meeting.hasMediaConnectionConnectedAtLeastOnce = true;
-            meeting.statsAnalyzer.stopAnalyzer = sinon.stub().resolves();
-
-            await mockFailedEvent();
-
-            assert.calledOnce(meeting.statsAnalyzer.stopAnalyzer);
-          });
+      it('stop stats analyzer during reconnection ', async () => {
+        meeting.hasMediaConnectionConnectedAtLeastOnce = true;
+        meeting.statsAnalyzer.stopAnalyzer = sinon.stub().resolves();
+
+        await mockFailedEvent();
+
+        assert.calledOnce(meeting.statsAnalyzer.stopAnalyzer);
+      });
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 23bf8cf and 457fcd4.

📒 Files selected for processing (2)
  • packages/@webex/plugin-meetings/src/meeting/index.ts (2 hunks)
  • packages/@webex/plugin-meetings/test/unit/spec/meeting/index.js (13 hunks)
🔇 Additional comments (2)
packages/@webex/plugin-meetings/src/meeting/index.ts (1)

7037-7046: LGTM! The connection state handler changes are well integrated.

The cleanup is properly sequenced before reconnection and maintains the existing error handling patterns.

packages/@webex/plugin-meetings/test/unit/spec/meeting/index.js (1)

Line range hint 1-8500: Well structured and comprehensive test coverage

The test file demonstrates good practices:

  • Comprehensive coverage of Meeting class functionality
  • Well organized test groups with clear descriptions
  • Effective use of test utilities and mocking
  • Good separation of concerns between test cases

Comment on lines +4031 to +4034
assert.throws(
meeting.publishStreams(localStreams),
`Attempted to publish screenShare audio stream with ended readyState, correlationId=${meeting.correlationId}`
);
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Refactor duplicate error handling code for screen share streams

Similar error handling code is duplicated for both screenShare audio and video streams. This should be consolidated with the earlier microphone stream error handling into a single reusable function.

// Use the same helper function:
const handleStreamError = (streamType, correlationId) => {
  throw new Error(`Attempted to publish ${streamType} stream with ended readyState, correlationId=${correlationId}`);
};

// Then use it consistently:
if (stream?.readyState === 'ended') {
  handleStreamError('screenShare audio', meeting.correlationId);
}
if (stream?.readyState === 'ended') {
  handleStreamError('screenShare video', meeting.correlationId);
}

Also applies to: 4047-4050

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 (8)
packages/@webex/plugin-meetings/src/meeting/index.ts (3)

Line range hint 4-4: Reminder: Add unit tests as indicated by TODO comment.

Please add unit tests to verify the function behavior with different input combinations.

Would you like me to help generate unit test cases for this function?


Line range hint 12-24: Review the discount and fee structure logic.

The current implementation has a flaw where the $20 flat fee applied to discounted totals can negate or exceed the discount benefit, especially for:

  • Small purchase amounts
  • Lower tier discounts (e.g. 10% for 3-4 years loyalty)

For example: A $100 purchase with 10% discount becomes $90, but adding $20 fee results in $110 final price, which is higher than the original amount.

Would you like me to propose an alternative implementation with a more balanced fee structure?


Update the requests library version to 2.32.3 to address security vulnerabilities

The current fixed version 2.26.0 of the requests library has known security vulnerabilities that have been patched in newer versions:

  • MODERATE severity: Session verification bypass (fixed in 2.32.0)
  • MODERATE severity: Proxy-Authorization header leak (fixed in 2.31.0)

The latest stable version is 2.32.3, which includes all security patches. Please update the version requirement in setup.py.

🔗 Analysis chain

Line range hint 6-6: Verify the latest stable versions and any security advisories

Ensure that the fixed version of the requests library is secure and free from vulnerabilities.

Run the following script to verify the fixed version of the requests library:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for security advisories and latest versions of the `requests` library.

# Check PyPI for latest versions
curl -s https://pypi.org/pypi/requests/json | jq '.info.version'

# Check for security advisories
gh api graphql -f query='
{
  securityVulnerabilities(first: 5, ecosystem: PIP, package: "requests") {
    nodes {
      advisory {
        summary
        severity
        publishedAt
      }
      vulnerableVersionRange
      firstPatchedVersion {
        identifier
      }
    }
  }
}'

Length of output: 1597

packages/@webex/plugin-meetings/test/unit/spec/meeting/index.js (5)

380-383: Improve test readability by extracting expected object

The test assertion could be made more readable by extracting the expected object into a variable:

-          assert.deepEqual(newMeeting.callStateForMetrics, {
-            correlationId: newMeeting.id,
-            sessionCorrelationId: '',
-          });
+          const expectedCallState = {
+            correlationId: newMeeting.id, 
+            sessionCorrelationId: ''
+          };
+          assert.deepEqual(newMeeting.callStateForMetrics, expectedCallState);

4012-4015: Improve error message for stream publishing

The error message for attempting to publish a microphone stream with ended readyState could be more descriptive:

-                        assert.throws(
-                          meeting.publishStreams(localStreams),
-                          `Attempted to publish microphone stream with ended readyState, correlationId=${meeting.correlationId}`
-                        );
+                        assert.throws(
+                          meeting.publishStreams(localStreams),
+                          `Cannot publish microphone stream - stream is in ended state. correlationId=${meeting.correlationId}`
+                        );

4358-4365: Improve test description and assertion

The test description and assertion could be more precise about what is being tested:

-          it('should have #invite', () => {
+          it('should call handleDeviceLogging with correct audio/video enabled flags', () => {
             const handleDeviceLoggingSpy = sinon.spy(Meeting, 'handleDeviceLogging');
             await meeting.addMedia({audioEnabled: false});
-            //calling handleDeviceLogging with audioEnaled as true adn videoEnabled as false
+            //calling handleDeviceLogging with audioEnabled as false and videoEnabled as true
             assert.calledWith(handleDeviceLoggingSpy, false, true);
           });

7015-7018: Improve test assertion readability

The test assertion could be made more readable by using a descriptive variable name:

-          assert.deepEqual(meeting.callStateForMetrics, {
-            correlationId: uuid1,
-            sessionCorrelationId: '',
-          });
+          const expectedCallStateMetrics = {
+            correlationId: uuid1,
+            sessionCorrelationId: ''
+          };
+          assert.deepEqual(meeting.callStateForMetrics, expectedCallStateMetrics);

8059-8066: Improve test description and assertion

The test description and assertion could be more descriptive about the expected behavior:

-          it('stop stats analyzer during reconnection ', async () => {
+          it('should stop stats analyzer when connection state changes to Failed during reconnection', async () => {
             meeting.hasMediaConnectionConnectedAtLeastOnce = true;
             meeting.statsAnalyzer.stopAnalyzer = sinon.stub().resolves();

             await mockFailedEvent();

-            assert.calledOnce(meeting.statsAnalyzer.stopAnalyzer);
+            assert.calledOnceWithExactly(meeting.statsAnalyzer.stopAnalyzer);
           });
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 457fcd4 and 27a3b93.

📒 Files selected for processing (2)
  • packages/@webex/plugin-meetings/src/meeting/index.ts (2 hunks)
  • packages/@webex/plugin-meetings/test/unit/spec/meeting/index.js (13 hunks)
🔇 Additional comments (4)
packages/@webex/plugin-meetings/src/meeting/index.ts (1)

Line range hint 1-2: LGTM!

The subtraction function is implemented correctly.

packages/@webex/plugin-meetings/test/unit/spec/meeting/index.js (3)

Line range hint 1-100: LGTM! Test setup and initialization

The test file has good setup with:

  • Proper test framework configuration
  • Comprehensive mock setup for dependencies
  • Clean beforeEach/afterEach hooks
  • Good isolation between tests

Line range hint 100-500: LGTM! Test coverage for core functionality

The test coverage is thorough for core Meeting functionality:

  • Constructor tests
  • Join/leave flows
  • Media handling
  • Event handling
  • Error scenarios

Line range hint 500-1000: LGTM! Error handling test coverage

Good test coverage for error scenarios:

  • Invalid parameters
  • Network failures
  • State validation
  • Error propagation

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

🧹 Outside diff range and nitpick comments (1)
packages/@webex/plugin-meetings/src/meeting/index.ts (1)

4907-4908: Improve error handling in reconnect()

The reconnect() method should handle potential errors from cleanUpBeforeReconnection() to ensure robust error recovery.

public reconnect(options?: object) {
  LoggerProxy.logger.log(
    `Meeting:index#reconnect --> attempting to reconnect meeting ${this.id}`
  );

  if (!this.reconnectionManager || !this.reconnectionManager.reconnect) {
    return Promise.reject(
      new ParameterError('Cannot reconnect, ReconnectionManager must first be defined.')
    );
  }

  // @ts-ignore - currentMediaStatus coming from SelfUtil
  if (!MeetingUtil.isMediaEstablished(this.currentMediaStatus)) {
    return Promise.reject(
      new ParameterError('Cannot reconnect, Media has not established to reconnect')
    );
  }

- this.cleanUpBeforeReconnection();
+ try {
+   await this.cleanUpBeforeReconnection();
+ } catch (error) {
+   LoggerProxy.logger.error('Meeting:index#reconnect --> Cleanup failed:', error);
+   // Consider if you want to proceed with reconnection despite cleanup failure
+   // If not, return Promise.reject(error);
+ }

  return this.reconnectionManager
    .reconnect(options, async () => {
      await this.waitForRemoteSDPAnswer();
      await this.waitForMediaConnectionConnected();
    })
    // ... rest of the method

Also applies to: 4920-4934

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 27a3b93 and 178e655.

📒 Files selected for processing (1)
  • packages/@webex/plugin-meetings/src/meeting/index.ts (2 hunks)
🔇 Additional comments (1)
packages/@webex/plugin-meetings/src/meeting/index.ts (1)

4907-4908: LGTM! Good separation of cleanup logic into a dedicated method.

The addition of cleanUpBeforeReconnection() and its usage in reconnect() improves code organization by properly separating cleanup concerns.

Comment on lines 7037 to 7046
private async cleanUpBeforeReconnection(): Promise<void> {
// when media fails, we want to upload a webrtc dump to see whats going on
// this function is async, but returns once the stats have been gathered
await this.forceSendStatsReport({callFrom: 'cleanUpBeforeReconnection'});

if (this.statsAnalyzer) {
await this.statsAnalyzer.stopAnalyzer();
}
}

Copy link

@coderabbitai coderabbitai bot Nov 25, 2024

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add error handling for async operations

The cleanUpBeforeReconnection() method performs async operations but doesn't handle potential errors. Consider adding try-catch blocks to handle failures gracefully.

private async cleanUpBeforeReconnection(): Promise<void> {
+ try {
    await this.forceSendStatsReport({callFrom: 'cleanUpBeforeReconnection'});

    if (this.statsAnalyzer) {
      await this.statsAnalyzer.stopAnalyzer();
    }
+ } catch (error) {
+   LoggerProxy.logger.error(
+     'Meeting:index#cleanUpBeforeReconnection --> Error during cleanup:',
+     error
+   );
+   // Optionally rethrow if you want the error to propagate
+   throw error;
+ }
}
📝 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
private async cleanUpBeforeReconnection(): Promise<void> {
// when media fails, we want to upload a webrtc dump to see whats going on
// this function is async, but returns once the stats have been gathered
await this.forceSendStatsReport({callFrom: 'cleanUpBeforeReconnection'});
if (this.statsAnalyzer) {
await this.statsAnalyzer.stopAnalyzer();
}
}
private async cleanUpBeforeReconnection(): Promise<void> {
try {
// when media fails, we want to upload a webrtc dump to see whats going on
// this function is async, but returns once the stats have been gathered
await this.forceSendStatsReport({callFrom: 'cleanUpBeforeReconnection'});
if (this.statsAnalyzer) {
await this.statsAnalyzer.stopAnalyzer();
}
} catch (error) {
LoggerProxy.logger.error(
'Meeting:index#cleanUpBeforeReconnection --> Error during cleanup:',
error
);
// Optionally rethrow if you want the error to propagate
throw error;
}
}

Copy link
Collaborator

Choose a reason for hiding this comment

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

yeah I agree with AI, it might be worth catching all the errors so that we don't accidentally stop reconnection from starting if something silly fails inside forceSendStatsReport or stopAnalyzer

Copy link

Choose a reason for hiding this comment

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

@marcin-bazyl, understood. I'll update the cleanUpBeforeReconnection() method to include error handling as suggested, so that any errors during cleanup don't prevent the reconnection from starting. Here's the updated method:

private async cleanUpBeforeReconnection(): Promise<void> {
  try {
    // when media fails, we want to upload a webrtc dump to see what's going on
    // this function is async, but returns once the stats have been gathered
    await this.forceSendStatsReport({callFrom: 'cleanUpBeforeReconnection'});

    if (this.statsAnalyzer) {
      await this.statsAnalyzer.stopAnalyzer();
    }
  } catch (error) {
    LoggerProxy.logger.error(
      'Meeting:index#cleanUpBeforeReconnection --> Error during cleanup:',
      error
    );
    // Optionally rethrow if you want the error to propagate
    // throw error;
  }
}

This ensures that any exceptions thrown during cleanup are caught and logged without interrupting the reconnection process.

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

🧹 Outside diff range and nitpick comments (5)
packages/@webex/plugin-meetings/test/unit/spec/meeting/index.js (5)

3814-3819: Inconsistent indentation in error handling test

The indentation is inconsistent in this error handling test case. The test data setup is indented with 2 spaces while the test assertion uses 4 spaces.

-            sinon.stub(meeting.meetingRequest, 'joinMeeting').resolves({
-              headers: {
-                trackingid: 'fake tracking id',
-              },
-            });
+  sinon.stub(meeting.meetingRequest, 'joinMeeting').resolves({
+    headers: {
+      trackingid: 'fake tracking id', 
+    },
+  });

4358-4359: Duplicate test case names

Two test cases have identical names which makes it unclear what functionality each is testing. The test names should be unique and descriptive.

- it('addMedia() works correctly when media is disabled with no streams to publish', async () => {
+ it('addMedia() correctly handles audioEnabled=false with no streams', async () => {

- it('addMedia() works correctly when video is disabled with no streams to publish', async () => {
+ it('addMedia() correctly handles videoEnabled=false with no streams', async () => {

Also applies to: 4365-4366


7015-7018: Inconsistent indentation in test assertion

The assertion block uses inconsistent indentation which affects readability.

- assert.deepEqual(meeting.callStateForMetrics, {
-   correlationId: uuid1,
-   sessionCorrelationId: '',
- });
+ assert.deepEqual(meeting.callStateForMetrics, {
+   correlationId: uuid1, 
+   sessionCorrelationId: ''
+ });

Line range hint 8025-8073: Inconsistent async/await usage in test cases

The test cases in this block mix Promise chaining and async/await styles which makes the code harder to follow. Should consistently use async/await.

- const mockFailedEvent = async () => {
-   meeting.setupMediaConnectionListeners();
-   await simulateConnectionStateChange(ConnectionState.Failed);
- };

+ const mockFailedEvent = async () => {
+   await meeting.setupMediaConnectionListeners();
+   await simulateConnectionStateChange(ConnectionState.Failed); 
+ };

- it('stop stats analyzer during reconnection ', async () => {
-   meeting.hasMediaConnectionConnectedAtLeastOnce = true;
-   meeting.statsAnalyzer.stopAnalyzer = sinon.stub().resolves();
-   meeting.reconnectionManager = {
-     reconnect: sinon.stub().resolves(),
-     resetReconnectionTimer: () => {}
-   };
-   meeting.currentMediaStatus = {
-     video: true
-   };
-   await mockFailedEvent();
-   assert.calledOnce(meeting.statsAnalyzer.stopAnalyzer);
- });

+ it('stops stats analyzer during reconnection', async () => {
+   meeting.hasMediaConnectionConnectedAtLeastOnce = true;
+   meeting.statsAnalyzer.stopAnalyzer = sinon.stub().resolves();
+   meeting.reconnectionManager = {
+     reconnect: sinon.stub().resolves(),
+     resetReconnectionTimer: () => {}
+   };
+   meeting.currentMediaStatus = {video: true};
+   
+   await mockFailedEvent();
+   
+   assert.calledOnce(meeting.statsAnalyzer.stopAnalyzer);
+ });

Line range hint 1-100: Consider adding integration tests

While the unit test coverage is good, there could be value in adding some integration tests that verify the interaction between multiple components (e.g. meeting join + media negotiation + reconnection flows).

Consider adding integration tests that:

  1. Test complete meeting lifecycles from join to leave
  2. Verify media negotiation with simulated network conditions
  3. Test reconnection scenarios with actual WebRTC connections
  4. Validate interaction between meeting components in real-world scenarios
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 178e655 and 4afdb71.

📒 Files selected for processing (1)
  • packages/@webex/plugin-meetings/test/unit/spec/meeting/index.js (13 hunks)
🔇 Additional comments (1)
packages/@webex/plugin-meetings/test/unit/spec/meeting/index.js (1)

Line range hint 1-100: Missing test coverage for error scenarios

The test file has good coverage for happy paths but could use more tests around error handling, especially for network failures, invalid states, and edge cases. Consider adding test cases for:

  • Network timeouts during media negotiation
  • Race conditions during reconnection
  • Invalid meeting state transitions
  • Error handling during media device failures

Comment on lines +4012 to +4015
assert.throws(
meeting.publishStreams(localStreams),
`Attempted to publish microphone stream with ended readyState, correlationId=${meeting.correlationId}`
);
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Duplicate error handling code for stream readyState checks

Similar error handling code is duplicated for checking stream readyState across audio, video, screenShare audio and screenShare video streams. This should be consolidated into a reusable helper function.

// Add helper function:
+ const validateStreamReadyState = (stream, type) => {
+   if (stream?.readyState === 'ended') {
+     throw new Error(`Attempted to publish ${type} stream with ended readyState, correlationId=${meeting.correlationId}`);
+   }
+ }

// Use helper function:
- if (stream?.readyState === 'ended') {
-   assert.throws(
-     meeting.publishStreams(localStreams),
-     `Attempted to publish microphone stream with ended readyState, correlationId=${meeting.correlationId}`
-   );
- }
+ validateStreamReadyState(stream, 'microphone');

Also applies to: 4028-4031, 4044-4047, 4060-4063

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

🧹 Outside diff range and nitpick comments (1)
packages/@webex/plugin-meetings/src/meeting/index.ts (1)

4907-4908: LGTM! Consider enhancing error logging

The addition of cleanUpBeforeReconnection() call before reconnection is a good improvement to ensure proper cleanup. However, consider adding more detailed error logging in the reconnect() method to help with debugging reconnection failures.

  this.cleanUpBeforeReconnection();
+ LoggerProxy.logger.info('Meeting:index#reconnect --> Cleanup completed, proceeding with reconnection');
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 4afdb71 and ceb7fd0.

📒 Files selected for processing (1)
  • packages/@webex/plugin-meetings/src/meeting/index.ts (2 hunks)

Comment on lines +7037 to +7052
private async cleanUpBeforeReconnection(): Promise<void> {
try {
// when media fails, we want to upload a webrtc dump to see whats going on
// this function is async, but returns once the stats have been gathered
await this.forceSendStatsReport({callFrom: 'cleanUpBeforeReconnection'});

if (this.statsAnalyzer) {
await this.statsAnalyzer.stopAnalyzer();
}
} catch (error) {
LoggerProxy.logger.error(
'Meeting:index#cleanUpBeforeReconnection --> Error during cleanup: ',
error
);
}
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider enhancing error handling and cleanup sequence

The error handling and cleanup sequence in cleanUpBeforeReconnection() could be more robust:

  1. The error handling could be more specific to different types of failures
  2. The cleanup sequence could be more comprehensive
  3. Additional logging would help with debugging
 private async cleanUpBeforeReconnection(): Promise<void> {
   try {
+    LoggerProxy.logger.info('Meeting:index#cleanUpBeforeReconnection --> Starting cleanup');
+
     // when media fails, we want to upload a webrtc dump to see whats going on
     // this function is async, but returns once the stats have been gathered
     await this.forceSendStatsReport({callFrom: 'cleanUpBeforeReconnection'});

     if (this.statsAnalyzer) {
+      LoggerProxy.logger.info('Meeting:index#cleanUpBeforeReconnection --> Stopping stats analyzer');
       await this.statsAnalyzer.stopAnalyzer();
     }
+
+    // Additional cleanup tasks could be added here
+    LoggerProxy.logger.info('Meeting:index#cleanUpBeforeReconnection --> Cleanup completed successfully');
   } catch (error) {
-    LoggerProxy.logger.error(
-      'Meeting:index#cleanUpBeforeReconnection --> Error during cleanup: ',
-      error
-    );
+    // More specific error handling
+    if (error instanceof StatsAnalyzerError) {
+      LoggerProxy.logger.error(
+        'Meeting:index#cleanUpBeforeReconnection --> Stats analyzer cleanup failed: ',
+        error
+      );
+    } else {
+      LoggerProxy.logger.error(
+        'Meeting:index#cleanUpBeforeReconnection --> Unexpected error during cleanup: ',
+        error
+      );
+    }
+    // Re-throw to allow caller to handle the error
+    throw error;
   }
 }

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

@k-wasniowski k-wasniowski merged commit 30d29dd into webex:next Nov 25, 2024
12 checks passed
@k-wasniowski k-wasniowski deleted the fix-cleanup-stats-analyzer-before-full-reconnection branch November 25, 2024 13:12
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