{"id":34212587,"url":"https://github.com/nodepassproject/npws","last_synced_at":"2026-02-14T17:15:24.622Z","repository":{"id":326797492,"uuid":"1106839285","full_name":"NodePassProject/npws","owner":"NodePassProject","description":"A high-performance, reliable WebSocket connection pool management system for Go applications.","archived":false,"fork":false,"pushed_at":"2025-12-22T01:58:44.000Z","size":38,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-01-13T18:26:48.598Z","etag":null,"topics":["network","pooling","websocket"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/NodePassProject.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-11-30T03:30:10.000Z","updated_at":"2025-12-22T01:57:58.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/NodePassProject/npws","commit_stats":null,"previous_names":["nodepassproject/npws"],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/NodePassProject/npws","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NodePassProject%2Fnpws","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NodePassProject%2Fnpws/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NodePassProject%2Fnpws/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NodePassProject%2Fnpws/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/NodePassProject","download_url":"https://codeload.github.com/NodePassProject/npws/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NodePassProject%2Fnpws/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29450845,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-14T15:52:44.973Z","status":"ssl_error","status_checked_at":"2026-02-14T15:52:11.208Z","response_time":53,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["network","pooling","websocket"],"created_at":"2025-12-15T21:24:15.029Z","updated_at":"2026-02-14T17:15:24.616Z","avatar_url":"https://github.com/NodePassProject.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# NPWS Package\r\n\r\n[![Go Reference](https://pkg.go.dev/badge/github.com/NodePassProject/npws.svg)](https://pkg.go.dev/github.com/NodePassProject/npws)\r\n[![License](https://img.shields.io/badge/License-BSD_3--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause)\r\n\r\nA high-performance, reliable WebSocket connection pool management system for Go applications.\r\n\r\n## Table of Contents\r\n\r\n- [Features](#features)\r\n- [Installation](#installation)\r\n- [Quick Start](#quick-start)\r\n- [Usage](#usage)\r\n  - [Client Connection Pool](#client-connection-pool)\r\n  - [Server Connection Pool](#server-connection-pool)\r\n  - [Managing Pool Health](#managing-pool-health)\r\n- [Security Features](#security-features)\r\n  - [Client IP Restriction](#client-ip-restriction)\r\n  - [TLS Security Modes](#tls-security-modes)\r\n- [Dynamic Adjustment](#dynamic-adjustment)\r\n- [Advanced Usage](#advanced-usage)\r\n- [Performance Considerations](#performance-considerations)\r\n- [Troubleshooting](#troubleshooting)\r\n- [Best Practices](#best-practices)\r\n  - [Pool Configuration](#1-pool-configuration)\r\n  - [Connection Management](#2-connection-management)\r\n  - [Error Handling and Monitoring](#3-error-handling-and-monitoring)\r\n  - [Production Deployment](#4-production-deployment)\r\n  - [Performance Optimization](#5-performance-optimization)\r\n  - [Testing and Development](#6-testing-and-development)\r\n- [License](#license)\r\n\r\n## Features\r\n\r\n- **Lock-free design** using atomic operations and `sync.Map` for maximum performance\r\n- **Thread-safe connection management** with automatic lifecycle handling\r\n- **Support for both client and server connection pools**\r\n- **Dynamic capacity and interval adjustment** based on real-time usage patterns\r\n- **Automatic connection health monitoring** with keep-alive support\r\n- **WebSocket connection pooling** with efficient ID-based retrieval\r\n- **4-byte hex connection identification** for efficient tracking\r\n- **Multiple TLS security modes** (self-signed, verified)\r\n- **Graceful error handling and recovery** with automatic retry mechanisms\r\n- **Configurable connection creation intervals** with dynamic adjustment\r\n- **Auto-reconnection** on connection failures\r\n- **Built-in keep-alive management** with configurable periods\r\n- **Zero lock contention** for high concurrency scenarios\r\n- **Client IP whitelisting** for server-side security\r\n\r\n## Installation\r\n\r\n```bash\r\ngo get github.com/NodePassProject/npws\r\n```\r\n\r\n## Quick Start\r\n\r\nHere's a minimal example to get you started:\r\n\r\n```go\r\npackage main\r\n\r\nimport (\r\n    \"log\"\r\n    \"time\"\r\n    \"github.com/NodePassProject/npws\"\r\n)\r\n\r\nfunc main() {\r\n    // Create client pool\r\n    minCap := 5\r\n    maxCap := 20\r\n    minInterval := 500 * time.Millisecond\r\n    maxInterval := 5 * time.Second\r\n    keepAlive := 30 * time.Second\r\n    tlsMode := \"2\" // TLS mode: \"1\" = self-signed, \"2\" = verified\r\n    serverURL := \"example.com:8443\"\r\n\r\n    clientPool := npws.NewClientPool(\r\n        minCap, maxCap,\r\n        minInterval, maxInterval,\r\n        keepAlive,\r\n        tlsMode,\r\n        serverURL,\r\n    )\r\n    defer clientPool.Close()\r\n\r\n    // Start client manager\r\n    go clientPool.ClientManager()\r\n\r\n    // Wait for pool to be ready\r\n    time.Sleep(2 * time.Second)\r\n\r\n    // Get connection by ID (received from server)\r\n    timeout := 10 * time.Second\r\n    conn, err := clientPool.OutgoingGet(\"a1b2c3d4\", timeout)\r\n    if err != nil {\r\n        log.Fatal(err)\r\n    }\r\n    defer conn.Close()\r\n\r\n    // Use connection...\r\n}\r\n```\r\n\r\n## Usage\r\n\r\n### Client Connection Pool\r\n\r\n```go\r\npackage main\r\n\r\nimport (\r\n    \"log\"\r\n    \"time\"\r\n    \"github.com/NodePassProject/npws\"\r\n)\r\n\r\nfunc main() {\r\n    // Configure client pool parameters\r\n    minCap := 5              // Minimum pool capacity\r\n    maxCap := 20             // Maximum pool capacity\r\n    minInterval := 500 * time.Millisecond  // Minimum creation interval\r\n    maxInterval := 5 * time.Second         // Maximum creation interval\r\n    keepAlive := 30 * time.Second          // Keep-alive period\r\n    tlsMode := \"2\"           // TLS mode: \"1\" = self-signed, \"2\" = verified\r\n    serverURL := \"example.com:8443\"        // Server address (host:port)\r\n\r\n    // Create client pool\r\n    clientPool := npws.NewClientPool(\r\n        minCap, maxCap,\r\n        minInterval, maxInterval,\r\n        keepAlive,\r\n        tlsMode,\r\n        serverURL,\r\n    )\r\n    defer clientPool.Close()\r\n\r\n    // Start pool manager in background\r\n    go clientPool.ClientManager()\r\n\r\n    // Wait for pool initialization\r\n    time.Sleep(2 * time.Second)\r\n\r\n    // Check pool status\r\n    if !clientPool.Ready() {\r\n        log.Fatal(\"Pool not ready\")\r\n    }\r\n\r\n    log.Printf(\"Pool active connections: %d\", clientPool.Active())\r\n    log.Printf(\"Pool capacity: %d\", clientPool.Capacity())\r\n    log.Printf(\"Pool interval: %v\", clientPool.Interval())\r\n\r\n    // Get connection by ID with timeout\r\n    timeout := 10 * time.Second\r\n    conn, err := clientPool.OutgoingGet(\"a1b2c3d4\", timeout)\r\n    if err != nil {\r\n        log.Printf(\"Connection not found: %v\", err)\r\n        return\r\n    }\r\n    defer conn.Close()\r\n\r\n    // Use connection for communication\r\n    _, err = conn.Write([]byte(\"Hello, Server!\"))\r\n    if err != nil {\r\n        log.Printf(\"Write error: %v\", err)\r\n        return\r\n    }\r\n\r\n    buf := make([]byte, 1024)\r\n    n, err := conn.Read(buf)\r\n    if err != nil {\r\n        log.Printf(\"Read error: %v\", err)\r\n        return\r\n    }\r\n    log.Printf(\"Received: %s\", string(buf[:n]))\r\n}\r\n```\r\n\r\n**Note:** `OutgoingGet` takes a connection ID and timeout duration, and returns `(net.Conn, error)`. \r\nThe error indicates if the connection with the specified ID was not found or if the timeout was exceeded.\r\n\r\n### Server Connection Pool\r\n\r\n```go\r\npackage main\r\n\r\nimport (\r\n    \"crypto/tls\"\r\n    \"log\"\r\n    \"net\"\r\n    \"time\"\r\n    \"github.com/NodePassProject/npws\"\r\n)\r\n\r\nfunc main() {\r\n    // Load TLS certificate\r\n    cert, err := tls.LoadX509KeyPair(\"server.crt\", \"server.key\")\r\n    if err != nil {\r\n        log.Fatal(err)\r\n    }\r\n\r\n    tlsConfig := \u0026tls.Config{\r\n        Certificates: []tls.Certificate{cert},\r\n        MinVersion:   tls.VersionTLS13,\r\n    }\r\n\r\n    // Create TCP listener\r\n    listener, err := net.Listen(\"tcp\", \"0.0.0.0:8443\")\r\n    if err != nil {\r\n        log.Fatal(err)\r\n    }\r\n\r\n    // Configure server pool\r\n    maxCap := 100                      // Maximum pool capacity\r\n    clientIP := \"\"                     // Client IP whitelist (\"\" = allow all)\r\n    keepAlive := 30 * time.Second      // Keep-alive period\r\n\r\n    // Create server pool\r\n    serverPool := npws.NewServerPool(\r\n        maxCap,\r\n        clientIP,\r\n        tlsConfig,\r\n        listener,\r\n        keepAlive,\r\n    )\r\n    if serverPool == nil {\r\n        log.Fatal(\"Failed to create server pool\")\r\n    }\r\n    defer serverPool.Close()\r\n\r\n    // Start server manager in background\r\n    go serverPool.ServerManager()\r\n\r\n    log.Printf(\"Server listening on %s\", listener.Addr())\r\n\r\n    // Accept connections from pool\r\n    for {\r\n        timeout := 30 * time.Second\r\n        id, conn, err := serverPool.IncomingGet(timeout)\r\n        if err != nil {\r\n            log.Printf(\"Failed to get connection: %v\", err)\r\n            continue\r\n        }\r\n\r\n        log.Printf(\"New connection: %s\", id)\r\n        go handleConnection(id, conn)\r\n    }\r\n}\r\n\r\nfunc handleConnection(id string, conn net.Conn) {\r\n    defer conn.Close()\r\n    \r\n    buf := make([]byte, 1024)\r\n    n, err := conn.Read(buf)\r\n    if err != nil {\r\n        log.Printf(\"Read error: %v\", err)\r\n        return\r\n    }\r\n    \r\n    log.Printf(\"Connection %s received: %s\", id, string(buf[:n]))\r\n    \r\n    // Echo back\r\n    _, err = conn.Write(buf[:n])\r\n    if err != nil {\r\n        log.Printf(\"Write error: %v\", err)\r\n    }\r\n}\r\n```\r\n\r\n**Note:** `IncomingGet` takes a timeout duration and returns `(string, net.Conn, error)`. The return values are:\r\n- `string`: The connection ID generated by the server (8-character hex string)\r\n- `net.Conn`: The connection object (wrapped WebSocket connection)\r\n- `error`: Can indicate timeout, context cancellation, or other pool-related errors\r\n\r\n### Managing Pool Health\r\n\r\n```go\r\n// Get a connection from client pool by ID with timeout\r\ntimeout := 10 * time.Second\r\nconn, err := clientPool.OutgoingGet(\"a1b2c3d4\", timeout)\r\nif err != nil {\r\n    // Connection with the specified ID not found or timeout exceeded\r\n    log.Printf(\"Connection not found: %v\", err)\r\n}\r\n\r\n// Get a connection from server pool with timeout\r\ntimeout := 30 * time.Second\r\nid, conn, err := serverPool.IncomingGet(timeout)\r\nif err != nil {\r\n    // Handle various error cases:\r\n    // - Pool is full or no connections available\r\n    // - Context cancelled\r\n    // - Timeout exceeded\r\n    log.Printf(\"Failed to get connection: %v\", err)\r\n}\r\n\r\n// Check if the pool is ready\r\nif clientPool.Ready() {\r\n    // The pool is initialized and ready for use\r\n}\r\n\r\n// Get current active connection count\r\nactiveConns := clientPool.Active()\r\n\r\n// Get current capacity setting\r\ncapacity := clientPool.Capacity()\r\n\r\n// Get current connection creation interval\r\ninterval := clientPool.Interval()\r\n\r\n// Manually flush all connections (rarely needed, closes all connections)\r\nclientPool.Flush()\r\n\r\n// Record an error (increases internal error counter)\r\nclientPool.AddError()\r\n\r\n// Get the current error count\r\nerrorCount := clientPool.ErrorCount()\r\n\r\n// Reset the error count to zero\r\nclientPool.ResetError()\r\n```\r\n\r\n## Security Features\r\n\r\n### Client IP Restriction\r\n\r\nThe `NewServerPool` function allows you to restrict incoming connections to a specific client IP address. The function signature is:\r\n\r\n```go\r\nfunc NewServerPool(\r\n    maxCap int,\r\n    clientIP string,\r\n    tlsConfig *tls.Config,\r\n    listener net.Listener,\r\n    keepAlive time.Duration,\r\n) *Pool\r\n```\r\n\r\n- `maxCap`: Maximum pool capacity.\r\n- `clientIP`: Restrict allowed client IP (\"\" for any).\r\n- `tlsConfig`: TLS configuration (required for secure connections).\r\n- `listener`: Network listener (TCP listener).\r\n- `keepAlive`: Keep-alive period.\r\n\r\nWhen the `clientIP` parameter is set:\r\n- All connections from other IP addresses will be immediately rejected with HTTP 403.\r\n- This provides an additional layer of security beyond network firewalls.\r\n- Particularly useful for internal services or dedicated client-server applications.\r\n\r\nTo allow connections from any IP address, use an empty string:\r\n\r\n```go\r\n// Create a server pool that accepts connections from any IP\r\nserverPool := npws.NewServerPool(\r\n    100, \r\n    \"\", \r\n    tlsConfig, \r\n    listener, \r\n    30*time.Second,\r\n)\r\n```\r\n\r\nTo restrict to a specific client IP:\r\n\r\n```go\r\n// Create a server pool that only accepts connections from 192.168.1.100\r\nserverPool := npws.NewServerPool(\r\n    100, \r\n    \"192.168.1.100\", \r\n    tlsConfig, \r\n    listener, \r\n    30*time.Second,\r\n)\r\n```\r\n\r\n### TLS Security Modes\r\n\r\n| Mode | Description | Security Level | Use Case |\r\n|------|-------------|----------------|----------|\r\n| `\"1\"` | Self-signed certificates (InsecureSkipVerify) | Medium | Development, testing environments |\r\n| `\"2\"` | Verified certificates | High | Production, public networks |\r\n\r\n**Note:** Both modes `\"1\"` and `\"2\"` use secure WebSocket (`wss://`) with TLS encryption.\r\n\r\n#### Example Usage\r\n\r\n```go\r\n// Self-signed TLS - development/testing (InsecureSkipVerify)\r\nclientPool := npws.NewClientPool(\r\n    5, 20, \r\n    500*time.Millisecond, 5*time.Second, \r\n    30*time.Second, \r\n    \"1\", \r\n    \"example.com:8443\",\r\n)\r\n\r\n// Verified TLS - production\r\nclientPool := npws.NewClientPool(\r\n    5, 20, \r\n    500*time.Millisecond, 5*time.Second, \r\n    30*time.Second, \r\n    \"2\", \r\n    \"example.com:8443\",\r\n)\r\n```\r\n\r\n---\r\n\r\n**Implementation Details:**\r\n\r\n- **Connection ID Generation:**\r\n  - The server generates a 4-byte random ID using `crypto/rand`\r\n  - Encoded as 8-character hexadecimal string (e.g., \"a1b2c3d4\")\r\n  - IDs are unique within the pool to prevent collisions\r\n  - Sent to client immediately after WebSocket handshake\r\n\r\n- **OutgoingGet Method:**\r\n  - For client pools: Returns `(net.Conn, error)` after retrieving a connection by ID.\r\n  - Takes timeout parameter to wait for connection availability.\r\n  - Removes connection from pool upon successful retrieval.\r\n\r\n- **IncomingGet Method:**\r\n  - For server pools: Returns `(string, net.Conn, error)` to get an available connection with its ID.\r\n  - Blocks until a connection is available or timeout occurs.\r\n  - Returns the connection ID and connection object for further use.\r\n\r\n- **Flush/Close:**\r\n  - `Flush` closes all connections and resets the pool.\r\n  - `Close` cancels the context, shuts down HTTP server, and flushes the pool.\r\n\r\n- **Dynamic Adjustment:**\r\n  - `adjustInterval` and `adjustCapacity` are used internally for pool optimization based on usage and success rate.\r\n\r\n- **Error Handling:**\r\n  - `AddError`, `ErrorCount`, and `ResetError` are thread-safe using atomic operations.\r\n\r\n- **WSConn Wrapper:**\r\n  - Wraps WebSocket connection to implement `net.Conn` interface.\r\n  - Provides `ConnectionState()` method for TLS connection state inspection.\r\n  - Preserves local and remote address information.\r\n\r\n## Dynamic Adjustment\r\n\r\nThe pool automatically adjusts parameters based on real-time metrics:\r\n\r\n### Interval Adjustment (per creation cycle)\r\n- **Decreases interval** (faster creation) when idle connections \u003c 20% of capacity\r\n  - Adjustment: `interval = max(interval - 100ms, minInterval)`\r\n- **Increases interval** (slower creation) when idle connections \u003e 80% of capacity\r\n  - Adjustment: `interval = min(interval + 100ms, maxInterval)`\r\n\r\n### Capacity Adjustment (after each creation attempt)\r\n- **Decreases capacity** when success rate \u003c 20%\r\n  - Adjustment: `capacity = max(capacity - 1, minCapacity)`\r\n- **Increases capacity** when success rate \u003e 80%\r\n  - Adjustment: `capacity = min(capacity + 1, maxCapacity)`\r\n\r\nMonitor adjustments:\r\n\r\n```go\r\n// Check current settings\r\ncurrentCapacity := clientPool.Capacity()   // Current target capacity\r\ncurrentInterval := clientPool.Interval()   // Current creation interval\r\nactiveConns := clientPool.Active()         // Available connections\r\n\r\n// Calculate utilization\r\nutilization := float64(activeConns) / float64(currentCapacity)\r\nlog.Printf(\"Pool: %d/%d connections (%.1f%%), %v interval\",\r\n    activeConns, currentCapacity, utilization*100, currentInterval)\r\n```\r\n\r\n## Advanced Usage\r\n\r\n### Custom Error Handling\r\n\r\n```go\r\npackage main\r\n\r\nimport (\r\n    \"log\"\r\n    \"time\"\r\n    \"github.com/NodePassProject/npws\"\r\n)\r\n\r\nfunc main() {\r\n    clientPool := npws.NewClientPool(\r\n        5, 20,\r\n        500*time.Millisecond, 5*time.Second,\r\n        30*time.Second,\r\n        \"2\",\r\n        \"example.com:8443\",\r\n    )\r\n    defer clientPool.Close()\r\n\r\n    go clientPool.ClientManager()\r\n\r\n    // Monitor error rate\r\n    go func() {\r\n        ticker := time.NewTicker(10 * time.Second)\r\n        defer ticker.Stop()\r\n        \r\n        for range ticker.C {\r\n            errorCount := clientPool.ErrorCount()\r\n            if errorCount \u003e 10 {\r\n                log.Printf(\"High error rate detected: %d errors\", errorCount)\r\n                clientPool.ResetError()\r\n                \r\n                // Take action: restart pool or alert\r\n                clientPool.Flush()\r\n            }\r\n        }\r\n    }()\r\n\r\n    // Your application logic...\r\n    time.Sleep(60 * time.Second)\r\n}\r\n```\r\n\r\n### Working with Context\r\n\r\n```go\r\npackage main\r\n\r\nimport (\r\n    \"context\"\r\n    \"log\"\r\n    \"time\"\r\n    \"github.com/NodePassProject/npws\"\r\n)\r\n\r\nfunc main() {\r\n    // Create a context that can be cancelled\r\n    ctx, cancel := context.WithCancel(context.Background())\r\n    defer cancel()\r\n\r\n    clientPool := npws.NewClientPool(\r\n        5, 20,\r\n        500*time.Millisecond, 5*time.Second,\r\n        30*time.Second,\r\n        \"1\",\r\n        \"example.com:8443\",\r\n    )\r\n\r\n    // Start manager\r\n    go clientPool.ClientManager()\r\n\r\n    // Graceful shutdown on signal\r\n    go func() {\r\n        \u003c-ctx.Done()\r\n        log.Println(\"Shutting down pool...\")\r\n        clientPool.Close()\r\n    }()\r\n\r\n    // Application runs until context is cancelled\r\n    \u003c-ctx.Done()\r\n}\r\n```\r\n\r\n### Load Balancing with Multiple Pools\r\n\r\n```go\r\npackage main\r\n\r\nimport (\r\n    \"sync/atomic\"\r\n    \"time\"\r\n    \"github.com/NodePassProject/npws\"\r\n)\r\n\r\nfunc main() {\r\n    // Create pools for different servers\r\n    pools := []*npws.Pool{\r\n        npws.NewClientPool(5, 20, 500*time.Millisecond, 5*time.Second, 30*time.Second, \"2\", \"server1.example.com:8443\"),\r\n        npws.NewClientPool(5, 20, 500*time.Millisecond, 5*time.Second, 30*time.Second, \"2\", \"server2.example.com:8443\"),\r\n        npws.NewClientPool(5, 20, 500*time.Millisecond, 5*time.Second, 30*time.Second, \"2\", \"server3.example.com:8443\"),\r\n    }\r\n\r\n    // Start all managers\r\n    for _, pool := range pools {\r\n        go pool.ClientManager()\r\n        defer pool.Close()\r\n    }\r\n\r\n    // Round-robin load balancing\r\n    var counter atomic.Uint32\r\n    getNextPool := func() *npws.Pool {\r\n        idx := counter.Add(1) % uint32(len(pools))\r\n        return pools[idx]\r\n    }\r\n\r\n    // Use pools in round-robin fashion\r\n    for i := 0; i \u003c 10; i++ {\r\n        pool := getNextPool()\r\n        \r\n        conn, err := pool.OutgoingGet(\"some-id\", 5*time.Second)\r\n        if err != nil {\r\n            pool.AddError()\r\n            continue\r\n        }\r\n        \r\n        // Use connection...\r\n        conn.Close()\r\n    }\r\n}\r\n```\r\n\r\n## Performance Considerations\r\n\r\n### Lock-Free Architecture\r\n\r\nThis package uses a **lock-free design** for maximum concurrency:\r\n\r\n| Component | Implementation | Benefit |\r\n|-----------|----------------|---------|\r\n| **Connection Storage** | `sync.Map` | Lock-free concurrent access |\r\n| **Counters** | `atomic.Int32` / `atomic.Int64` | Lock-free increments |\r\n| **ID Channel** | Buffered `chan string` | Native Go concurrency |\r\n\r\n**Performance Impact:**\r\n- Zero lock contention in high-concurrency scenarios\r\n- No context switching overhead from mutex waits\r\n- Scales linearly with CPU cores\r\n- Consistent sub-microsecond operation latency\r\n\r\n### Connection Pool Sizing\r\n\r\n| Pool Size | Pros | Cons | Best For |\r\n|-----------|------|------|----------|\r\n| Too Small (\u003c 5) | Low resource usage | Connection contention, delays | Low-traffic applications |\r\n| Optimal (5-50) | Balanced performance | Requires monitoring | Most applications |\r\n| Too Large (\u003e 100) | No contention | Resource waste, memory overhead | Very high-traffic services |\r\n\r\n**Sizing Guidelines:**\r\n- Start with `minCap = baseline_load` and `maxCap = peak_load × 1.5`\r\n- Monitor connection usage with `pool.Active()` and `pool.Capacity()`\r\n- Adjust based on observed patterns\r\n\r\n### WebSocket Performance Impact\r\n\r\n| Aspect | WebSocket | Plain TCP |\r\n|--------|-----------|-----------|\r\n| **Handshake Time** | ~50-100ms (HTTP upgrade) | ~10-20ms (direct) |\r\n| **Protocol Overhead** | Minimal (frame headers) | None |\r\n| **Browser Compatibility** | Excellent | Limited |\r\n| **Firewall Traversal** | Easy (HTTP ports) | May be blocked |\r\n| **Throughput** | ~95% of TCP | Baseline |\r\n\r\n### Connection Creation Overhead\r\n\r\nConnection creation in WebSocket involves:\r\n- **Cost**: ~50-100ms per connection (HTTP upgrade + TLS handshake)\r\n- **Frequency**: Controlled by pool intervals\r\n- **Trade-off**: Fast creation vs. resource usage\r\n\r\nFor ultra-high-throughput systems, consider pre-creating connections during idle periods.\r\n\r\n## Troubleshooting\r\n\r\n### Common Issues\r\n\r\n#### 1. Connection Timeout\r\n**Symptoms:** WebSocket connection fails to establish  \r\n**Solutions:**\r\n- Check network connectivity to target host\r\n- Verify server address and port are correct\r\n- Ensure firewall allows WebSocket connections\r\n- Check for proxy/NAT issues\r\n\r\n#### 2. TLS Handshake Failure\r\n**Symptoms:** Connections fail with certificate errors  \r\n**Solutions:**\r\n- Verify certificate validity and expiration\r\n- Check hostname matches certificate Common Name\r\n- Ensure TLS 1.3 is supported\r\n- For testing, temporarily use TLS mode `\"1\"` (InsecureSkipVerify)\r\n\r\n#### 3. Pool Exhaustion\r\n**Symptoms:** `IncomingGet()` returns timeout error  \r\n**Solutions:**\r\n- Check WebSocket server status\r\n- Increase maximum capacity\r\n- Reduce connection hold time in application code\r\n- Check for connection leaks (ensure connections are properly closed)\r\n- Monitor with `pool.Active()`, `pool.Capacity()`\r\n- Use appropriate timeout values with `IncomingGet(timeout)`\r\n\r\n#### 4. High Error Rate\r\n**Symptoms:** Frequent connection creation failures  \r\n**Solutions:**\r\n- Check WebSocket server stability\r\n- Monitor network connectivity\r\n- Verify server is accepting connections\r\n- Track errors with `pool.AddError()` and `pool.ErrorCount()`\r\n\r\n#### 5. HTTP Server Closed Error\r\n**Symptoms:** Server manager stops with \"http: Server closed\"  \r\n**Solutions:**\r\n- Normal behavior when `Close()` is called\r\n- Check context cancellation\r\n- Review graceful shutdown procedures\r\n\r\n### Debugging Checklist\r\n\r\n- [ ] **Network connectivity**: Can you reach the target host?\r\n- [ ] **Port accessibility**: Is the WebSocket port open and not blocked?\r\n- [ ] **Certificate validity**: For TLS, are certificates valid and not expired?\r\n- [ ] **Pool capacity**: Is `maxCap` sufficient for your load?\r\n- [ ] **Connection leaks**: Are you properly closing connections?\r\n- [ ] **Error monitoring**: Are you tracking `pool.ErrorCount()`?\r\n- [ ] **Firewall/Proxy**: Are there WebSocket-specific restrictions?\r\n\r\n### Debug Logging\r\n\r\nAdd logging at key points for better debugging:\r\n\r\n```go\r\n// Log successful connection retrieval\r\nid, conn, err := serverPool.IncomingGet(30 * time.Second)\r\nif err != nil {\r\n    log.Printf(\"Connection retrieval failed: %v\", err)\r\n    serverPool.AddError()\r\n} else {\r\n    log.Printf(\"Connection retrieved successfully: %s\", id)\r\n}\r\n\r\n// Monitor pool health\r\nticker := time.NewTicker(10 * time.Second)\r\ngo func() {\r\n    for range ticker.C {\r\n        log.Printf(\"Pool status - Active: %d, Capacity: %d, Interval: %v, Errors: %d\",\r\n            pool.Active(), pool.Capacity(), pool.Interval(), pool.ErrorCount())\r\n    }\r\n}()\r\n```\r\n\r\n## Best Practices\r\n\r\n### 1. Pool Configuration\r\n\r\n#### Capacity Sizing\r\n```go\r\n// For most applications, start with these guidelines:\r\nminCap := expectedConcurrentConnections\r\nmaxCap := peakConcurrentConnections * 1.5\r\n\r\n// Example for a web service handling 50 concurrent connections\r\nclientPool := npws.NewClientPool(\r\n    50, 75,                             // min/max capacity\r\n    500*time.Millisecond,               // min interval\r\n    5*time.Second,                      // max interval\r\n    30*time.Second,                     // keep-alive\r\n    \"2\",                                // verified TLS\r\n    \"api.example.com:8443\",             // server address\r\n)\r\n\r\n// For high-traffic API handling 200 concurrent connections\r\nhighTrafficPool := npws.NewClientPool(\r\n    150, 300,                           // min/max capacity\r\n    200*time.Millisecond,               // min interval (faster)\r\n    3*time.Second,                      // max interval\r\n    30*time.Second,                     // keep-alive\r\n    \"2\",                                // verified TLS\r\n    \"api.example.com:8443\",             // server address\r\n)\r\n\r\nlog.Printf(\"Pool created with capacity %d-%d\", minCap, maxCap)\r\n```\r\n\r\n#### Interval Configuration\r\n```go\r\n// Aggressive (high-frequency applications)\r\nminInterval := 100 * time.Millisecond\r\nmaxInterval := 1 * time.Second\r\n\r\n// Balanced (general purpose)\r\nminInterval := 500 * time.Millisecond\r\nmaxInterval := 5 * time.Second\r\n\r\n// Conservative (low-frequency, batch processing)\r\nminInterval := 2 * time.Second\r\nmaxInterval := 10 * time.Second\r\n```\r\n\r\n#### Leverage Lock-Free Architecture\r\n```go\r\n// The lock-free design allows safe concurrent access to pool metrics\r\n// No need to worry about mutex contention or race conditions\r\n\r\nfunc monitorPoolMetrics(pool *npws.Pool) {\r\n    ticker := time.NewTicker(1 * time.Second)\r\n    defer ticker.Stop()\r\n    \r\n    for range ticker.C {\r\n        // All these operations are lock-free and thread-safe\r\n        active := pool.Active()\r\n        capacity := pool.Capacity()\r\n        interval := pool.Interval()\r\n        errors := pool.ErrorCount()\r\n        \r\n        log.Printf(\"Pool metrics - Active: %d, Cap: %d, Interval: %v, Errors: %d\",\r\n            active, capacity, interval, errors)\r\n    }\r\n}\r\n```\r\n\r\n### 2. Connection Management\r\n\r\n#### Always Close Connections\r\n```go\r\n// GOOD: Always close connections\r\nid, conn, err := serverPool.IncomingGet(30 * time.Second)\r\nif err != nil {\r\n    log.Printf(\"Failed to get connection: %v\", err)\r\n    return err\r\n}\r\nif conn != nil {\r\n    defer conn.Close()  // Close the connection when done\r\n    // Use connection...\r\n}\r\n\r\n// BAD: Forgetting to close connections leads to resource leaks\r\nid, conn, _ := serverPool.IncomingGet(30 * time.Second)\r\n// Missing Close() - causes resource leak!\r\n```\r\n\r\n#### Handle Timeouts Gracefully\r\n```go\r\n// Use reasonable timeouts for IncomingGet\r\ntimeout := 10 * time.Second\r\nid, conn, err := serverPool.IncomingGet(timeout)\r\nif err != nil {\r\n    log.Printf(\"Connection timeout: %v\", err)\r\n    serverPool.AddError()\r\n    return err\r\n}\r\nif conn == nil {\r\n    log.Printf(\"Unexpected nil connection\")\r\n    return errors.New(\"unexpected nil connection\")\r\n}\r\ndefer conn.Close()\r\n```\r\n\r\n### 3. Error Handling and Monitoring\r\n\r\n#### Implement Comprehensive Error Tracking\r\n```go\r\ntype PoolManager struct {\r\n    pool        *npws.Pool\r\n    maxErrors   int\r\n    logger      *log.Logger\r\n}\r\n\r\nfunc (pm *PoolManager) getConnectionWithRetry(id string, maxRetries int) (net.Conn, error) {\r\n    for i := 0; i \u003c maxRetries; i++ {\r\n        conn, err := pm.pool.OutgoingGet(id, 5*time.Second)\r\n        if err == nil {\r\n            return conn, nil\r\n        }\r\n        \r\n        pm.pool.AddError()\r\n        pm.logger.Printf(\"Retry %d/%d: %v\", i+1, maxRetries, err)\r\n        time.Sleep(time.Duration(i+1) * 100 * time.Millisecond)\r\n    }\r\n    \r\n    return nil, errors.New(\"max retries exceeded\")\r\n}\r\n\r\n// Monitor pool health periodically\r\nfunc (pm *PoolManager) healthCheck() {\r\n    ticker := time.NewTicker(30 * time.Second)\r\n    defer ticker.Stop()\r\n    \r\n    for range ticker.C {\r\n        errorCount := pm.pool.ErrorCount()\r\n        active := pm.pool.Active()\r\n        capacity := pm.pool.Capacity()\r\n        \r\n        if errorCount \u003e pm.maxErrors {\r\n            pm.logger.Printf(\"High error rate: %d errors\", errorCount)\r\n            pm.pool.Flush()\r\n            pm.pool.ResetError()\r\n        }\r\n        \r\n        utilization := float64(active) / float64(capacity) * 100\r\n        pm.logger.Printf(\"Pool health - Utilization: %.1f%%, Errors: %d\",\r\n            utilization, errorCount)\r\n    }\r\n}\r\n```\r\n\r\n### 4. Production Deployment\r\n\r\n#### Security Configuration\r\n```go\r\n// Production server setup with proper TLS\r\nfunc createProductionServer() (*npws.Pool, error) {\r\n    // Load production certificates\r\n    cert, err := tls.LoadX509KeyPair(\"server.crt\", \"server.key\")\r\n    if err != nil {\r\n        return nil, err\r\n    }\r\n    \r\n    tlsConfig := \u0026tls.Config{\r\n        Certificates: []tls.Certificate{cert},\r\n        MinVersion:   tls.VersionTLS13,\r\n        CipherSuites: []uint16{\r\n            tls.TLS_AES_128_GCM_SHA256,\r\n            tls.TLS_AES_256_GCM_SHA384,\r\n            tls.TLS_CHACHA20_POLY1305_SHA256,\r\n        },\r\n    }\r\n    \r\n    listener, err := net.Listen(\"tcp\", \"0.0.0.0:8443\")\r\n    if err != nil {\r\n        return nil, err\r\n    }\r\n    \r\n    // Restrict to specific client IP for security\r\n    return npws.NewServerPool(\r\n        100,\r\n        \"192.168.1.100\", // Only allow this client\r\n        tlsConfig,\r\n        listener,\r\n        30*time.Second,\r\n    ), nil\r\n}\r\n\r\n// Client with verified certificates\r\nfunc createProductionClient() *npws.Pool {\r\n    return npws.NewClientPool(\r\n        20, 50,\r\n        500*time.Millisecond,\r\n        5*time.Second,\r\n        30*time.Second,\r\n        \"2\", // Verified TLS\r\n        \"api.example.com:8443\",\r\n    )\r\n}\r\n```\r\n\r\n#### Graceful Shutdown\r\n```go\r\nfunc (app *Application) Shutdown(ctx context.Context) error {\r\n    // Stop accepting new requests first\r\n    app.isShuttingDown.Store(true)\r\n    \r\n    // Give existing connections time to complete\r\n    shutdownTimeout := 10 * time.Second\r\n    shutdownCtx, cancel := context.WithTimeout(ctx, shutdownTimeout)\r\n    defer cancel()\r\n    \r\n    // Close all pools\r\n    for _, pool := range app.pools {\r\n        pool.Close()\r\n    }\r\n    \r\n    \u003c-shutdownCtx.Done()\r\n    return nil\r\n}\r\n```\r\n\r\n### 5. Performance Optimization\r\n\r\n#### Avoid Common Anti-patterns\r\n```go\r\n// ANTI-PATTERN: Creating pools repeatedly\r\nfunc badHandler(w http.ResponseWriter, r *http.Request) {\r\n    // DON'T: Create a new pool for each request\r\n    pool := npws.NewClientPool(5, 20, 500*time.Millisecond, 5*time.Second, 30*time.Second, \"2\", \"server:8443\")\r\n    defer pool.Close()\r\n}\r\n\r\n// GOOD PATTERN: Reuse pools\r\ntype Server struct {\r\n    wsPool *npws.Pool // Shared pool instance\r\n}\r\n\r\nfunc (s *Server) goodHandler(w http.ResponseWriter, r *http.Request) {\r\n    // DO: Reuse existing pool\r\n    conn, err := s.wsPool.OutgoingGet(\"conn-id\", 5*time.Second)\r\n    if err != nil {\r\n        http.Error(w, err.Error(), http.StatusServiceUnavailable)\r\n        return\r\n    }\r\n    defer conn.Close()\r\n    \r\n    // Handle request...\r\n}\r\n```\r\n\r\n#### Optimize for Your Use Case\r\n```go\r\n// High-throughput, low-latency services\r\nhighThroughputPool := npws.NewClientPool(\r\n    100, 200,                           // Large capacity\r\n    100*time.Millisecond,               // Fast creation\r\n    1*time.Second,                      // Quick adjustment\r\n    15*time.Second,                     // Short keep-alive\r\n    \"2\",\r\n    \"api.example.com:8443\",\r\n)\r\n\r\n// Long-running, stable connections\r\nstablePool := npws.NewClientPool(\r\n    10, 20,                             // Smaller capacity\r\n    1*time.Second,                      // Slower creation\r\n    10*time.Second,                     // Longer adjustment\r\n    60*time.Second,                     // Long keep-alive\r\n    \"2\",\r\n    \"backend.example.com:8443\",\r\n)\r\n\r\n// Batch processing with bursts\r\nbatchPool := npws.NewClientPool(\r\n    5, 50,                              // Wide capacity range\r\n    2*time.Second,                      // Slow baseline\r\n    10*time.Second,                     // Wide adjustment range\r\n    30*time.Second,                     // Standard keep-alive\r\n    \"2\",\r\n    \"batch.example.com:8443\",\r\n)\r\n```\r\n\r\n### 6. Testing and Development\r\n\r\n#### Use Development Mode\r\n```go\r\n// Development setup with relaxed security\r\nfunc createDevPool() *npws.Pool {\r\n    return npws.NewClientPool(\r\n        2, 5,                           // Small capacity for testing\r\n        1*time.Second,                  // Slow intervals for observation\r\n        5*time.Second,\r\n        10*time.Second,                 // Short keep-alive\r\n        \"1\",                            // Self-signed certs (InsecureSkipVerify)\r\n        \"localhost:8443\",\r\n    )\r\n}\r\n```\r\n\r\n#### Integration Testing\r\n```go\r\nfunc TestPoolIntegration(t *testing.T) {\r\n    // Setup server\r\n    cert, err := tls.LoadX509KeyPair(\"testdata/server.crt\", \"testdata/server.key\")\r\n    if err != nil {\r\n        t.Fatal(err)\r\n    }\r\n    \r\n    tlsConfig := \u0026tls.Config{\r\n        Certificates: []tls.Certificate{cert},\r\n        MinVersion:   tls.VersionTLS13,\r\n    }\r\n    \r\n    listener, err := net.Listen(\"tcp\", \"127.0.0.1:0\")\r\n    if err != nil {\r\n        t.Fatal(err)\r\n    }\r\n    \r\n    serverPool := npws.NewServerPool(10, \"\", tlsConfig, listener, 10*time.Second)\r\n    go serverPool.ServerManager()\r\n    defer serverPool.Close()\r\n    \r\n    // Setup client\r\n    clientPool := npws.NewClientPool(\r\n        2, 5,\r\n        500*time.Millisecond, 2*time.Second,\r\n        10*time.Second,\r\n        \"1\",  // Self-signed certs for testing\r\n        listener.Addr().String(),\r\n    )\r\n    go clientPool.ClientManager()\r\n    defer clientPool.Close()\r\n    \r\n    // Wait for pool initialization\r\n    time.Sleep(2 * time.Second)\r\n    \r\n    // Test connection flow\r\n    id, conn, err := serverPool.IncomingGet(5 * time.Second)\r\n    if err != nil {\r\n        t.Fatalf(\"Failed to get connection: %v\", err)\r\n    }\r\n    defer conn.Close()\r\n    \r\n    t.Logf(\"Connection established with ID: %s\", id)\r\n}\r\n```\r\n\r\n## License\r\n\r\nThis project is licensed under the BSD 3-Clause License.  \r\nSee the [LICENSE](LICENSE) file for details.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnodepassproject%2Fnpws","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnodepassproject%2Fnpws","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnodepassproject%2Fnpws/lists"}