Skip to content

Refactor promise handling in Communicator class#97

Merged
samchon merged 1 commit intosamchon:masterfrom
Neschadin:fix/communicator-unhandled-rejections
Dec 15, 2025
Merged

Refactor promise handling in Communicator class#97
samchon merged 1 commit intosamchon:masterfrom
Neschadin:fix/communicator-unhandled-rejections

Conversation

@Neschadin
Copy link
Copy Markdown

Fix: Prevent unhandled promise rejections in Communicator methods

Problem

Two methods in Communicator class had error handling issues:

  1. _Call_function: Used an anti-pattern new Promise(async (resolve, reject) => { await this.sendData(...) })
  2. _Send_return: Missing error handling for await this.sendData(...) calls

This causes unhandled promise rejections when:

  • WebSocket connection is closed while sending data
  • sendData() throws an error (e.g., connection state is CLOSED)
  • The error occurs asynchronously and isn't caught properly

Impact

  • Applications using TGrid crash with unhandled rejection errors
  • Production environments require global unhandledRejection handlers as workaround
  • Poor error handling experience for developers

Example Error

Error: Error on WebSocketAcceptor.Communicator._Call_fuction(): the connection has been closed.
    at WebSocketAcceptor.AcceptorBase.inspectReady
    at WebSocketAcceptor.Communicator._Call_function

Solution

1. Fixed _Call_function method

Replaced the async Promise executor pattern with explicit error handling:

Before:

return new Promise(async (resolve, reject) => {
  // ...
  await this.sendData(invoke);  // ❌ Errors not caught
});

After:

return new Promise((resolve, reject) => {
  // ...
  Promise.resolve(this.sendData(invoke)).catch((error) => {
    this.promises_.erase(invoke.uid);  // Clean up reservation
    reject(error);  // Properly reject the promise
  });
});

2. Fixed _Send_return method

Added error handling for sendData() calls when sending return values:

Before:

// RETURNS
await this.sendData(props.return);  // ❌ Errors not caught

After:

// RETURNS
// Handle sendData errors to prevent unhandled rejections when connection is closed
try {
  await this.sendData(props.return);
} catch (error) {
  // If sendData fails (e.g., connection closed), silently fail
  // The error is already handled by the connection state management
}

Benefits

  1. Proper error handling: All errors from sendData() are caught and handled
  2. No unhandled rejections: Errors are properly propagated through Promise chain
  3. Resource cleanup: Promise reservations are cleaned up on error
  4. Follows best practices: Avoids the async Promise executor anti-pattern

Testing

  • Tested with closed WebSocket connections
  • Verified no unhandled rejections occur
  • Confirmed errors are properly caught and rejected
  • Checked promise reservation cleanup on error

Related Issues

This fix addresses the common issue where applications using TGrid need to implement global unhandledRejection handlers to prevent crashes when connections close unexpectedly.

- Removed unnecessary async from the promise constructor in _Call_function.
- Improved error handling in sendData calls by using Promise.resolve and catch.
- Added try-catch block around sendData in the return handling to prevent unhandled promise rejections.
@samchon samchon requested a review from Copilot December 15, 2025 03:12
@samchon samchon added bug Something isn't working enhancement New feature or request labels Dec 15, 2025
Copy link
Copy Markdown
Owner

@samchon samchon left a comment

Choose a reason for hiding this comment

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

Thanks for fixing

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR refactors promise handling in the Communicator class to prevent unhandled promise rejections that occur when WebSocket connections close unexpectedly during data transmission. The fix addresses two critical methods where errors from sendData() were not properly caught, leading to application crashes in production environments.

Key Changes:

  • Removed the async Promise executor anti-pattern from _Call_function method
  • Added proper error handling and promise cleanup when sendData() fails in _Call_function
  • Added try-catch wrapper around sendData() calls in _Send_return method to handle closed connections

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

await this.sendData(props.return);
try {
await this.sendData(props.return);
} catch {}
Copy link

Copilot AI Dec 15, 2025

Choose a reason for hiding this comment

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

The empty catch block silently swallows all errors from sendData(). While this might be intentional for handling closed connections, it makes debugging difficult and hides unexpected errors. Consider at minimum logging the error at debug/trace level, or checking the error type to only swallow expected connection-closed errors. This would help developers troubleshoot issues where sendData() fails for unexpected reasons (e.g., serialization errors, network issues).

Suggested change
} catch {}
} catch (error) {
console.debug("Failed to send data in _Send_return:", error);
}

Copilot uses AI. Check for mistakes.
@samchon samchon merged commit f500c27 into samchon:master Dec 15, 2025
11 checks passed
Copy link
Copy Markdown
Owner

@samchon samchon left a comment

Choose a reason for hiding this comment

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

I will publish it as v1.2.1. When using it, if something unexpected happened, please tell me.

I will also test this on my another project autobe

@Neschadin Neschadin deleted the fix/communicator-unhandled-rejections branch December 16, 2025 10:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants