Skip to content

Conversation

@vigodsky
Copy link
Contributor

@vigodsky vigodsky commented Oct 18, 2025

Hello,

This PR introduces multiplexed WebSocket connection via channels.

Key Features

🔄 Multiplexing Channels: Multiple services can now share a single WebSocket connection, significantly reducing connection overhead.

🎯 Unique Request ID Matching: Critical requirement - each request MUST use a unique ID for proper request/response correlation. The system now routes responses directly to the
requesting service using waiter channels.

🔧 Backward Compatibility: Added function options pattern to maintain compatibility with existing code while enabling new multiplexing features.

Technical Implementation

  • Waiter Channels: New WithWaiter() option allows services to receive responses directly via dedicated channels instead of the global read channel
  • Request Options: Introduced RequestOption functional pattern for extensible request configuration
  • Service Options: Added WithWebSocketClient() to allow services to share WebSocket client instances

Changes Overview

  • Modified all WebSocket services (order_place, order_cancel, order_status, etc.) to support optional shared client
  • Added comprehensive example demonstrating concurrent request handling
  • Updated client interface to support request options with backward compatibility
  • Enhanced error handling and debugging for multiplexed scenarios

⚠️ Important Usage Notes

  • Unique IDs are mandatory - using duplicate request IDs will result in ErrorWsIdAlreadySent
  • Services can operate in two modes: dedicated connection or shared connection
  • Waiter channels provide 1:1 request/response matching for reliable concurrent operations
  • Do not close waiter from application side, actually ws client owns it and only read handler (which is writes into waiter channel) allowed to close

Testing

  • Added benchmarking for request list operations
  • Comprehensive multiplexed WebSocket example with concurrent order operations
  • Mock client updates to support new interface

Simple Waiter Channel Usage Example

  // 1. Create a shared WebSocket client (one connection for multiple services)
  client, err := websocket.NewClient(conn)

  // 2. Create services that share the same WebSocket connection
  orderService, err := futures.NewOrderPlaceWsService(
      apiKey, secretKey,
      websocket.WithWebSocketClient(client),  // Share connection
  )

  // 3. Create dedicated waiter channel for this service
  waiterChannel := make(chan []byte, 10)

  // 4. Send request with unique ID and waiter channel
  requestID := "unique_order_123"
  request := futures.NewOrderPlaceWsRequest().Symbol("BTCUSDT").Side(futures.SideTypeBuy)

  // ✨ Key: Use WithWaiter() to route response to your channel instead of global channel
  err = orderService.Do(requestID, request, websocket.WithWaiter(waiterChannel))

  // 5. Receive response directly on your dedicated channel
  select {
  case response := <-waiterChannel:
      // Handle response for requestID "unique_order_123"
      fmt.Printf("Got response: %s", string(response))
  case <-time.After(30 * time.Second):
      // Timeout handling
  }

@vigodsky vigodsky marked this pull request as ready for review October 18, 2025 11:49
@vigodsky
Copy link
Contributor Author

Hi @carlosmiei , @sc0Vu !

I noticed that many people asked about sharing ws connection between services, so it can be useful. Kindly ask you to have a look, thank you.
If you need more examples/documentation let me know, I can add to PR description or in repository.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant