# Migration Guide: ProxyPool → SmartPool Hướng dẫn chi tiết để migrate code client từ ProxyPool (legacy) sang SmartPool (new system). --- ## 📋 Tổng Quan ### ProxyPool (Legacy System) - ❌ Không có SDK client, phải tự implement gRPC/HTTP client - ❌ Field names: PascalCase (`AccessToken`, `Host`, `Port`) - ❌ Strategies: `random`, `round_robin`, `least_used`, `least_delay`, `least_response_time` - ❌ Không có client-side caching, batch logging, connection pooling tự động - ✅ Đơn giản, phù hợp cho use cases cơ bản ### SmartPool (New System) - ✅ SDK client với nhiều tính năng tối ưu - ✅ Field names: snake_case (`access_token`, `host`, `port`) - ✅ Strategies: `round_robin` (default), `random`, `least_delay`, `adaptive_ranking`, `alternative` - ✅ Client-side caching, batch logging, connection pooling tự động - ✅ Exception handling chi tiết với typed exceptions - ✅ Performance cao hơn ~30-50% --- ## 🔄 Migration Steps ### Step 1: Cài Đặt NuGet Package **Trước (ProxyPool):** ```xml ``` **Sau (SmartPool):** ```xml ``` ### Step 2: Cập Nhật Configuration **Trước (ProxyPool):** ```json { "TokenPoolOptions": { "Host": "10.9.3.70", "Port": 31287, "protocol": "Grpc" } } ``` **Sau (SmartPool):** ```json { "SmartPool": { "Protocol": "Grpc", "Host": "10.9.3.70", "Port": 5001, "UseSecureConnection": false, "TimeoutMs": 30000, "EnableClientCache": true, "ClientCacheDurationSeconds": 30, "EnableBatchLogging": true, "LogBatchSize": 50, "EnableFireAndForgetLogging": true } } ``` **Lưu ý:** - SmartPool sử dụng port khác (5001 cho gRPC, 5000 cho HTTP) - Cần cấu hình `ConfigManager:AccessToken` nếu muốn tự động inject vào requests ### Step 3: Cập Nhật Service Registration **Trước (ProxyPool - gRPC):** ```csharp using Icomm.ResourcePool.Abstractions; using MagicOnion.Client; using Grpc.Net.Client; // Manual gRPC client setup var channel = GrpcChannel.ForAddress("http://10.9.3.70:31287"); var client = MagicOnionClient.Create(channel); ``` **Sau (SmartPool):** ```csharp using Icomm.SmartPool.Proxy.Extensions; // In Startup.cs or Program.cs services.AddSmartPoolClient(configuration); // Or with explicit options services.AddSmartPoolClient(configuration, options => { options.Protocol = SmartPoolProtocol.Grpc; options.Host = "10.9.3.70"; options.Port = 5001; }); ``` ### Step 4: Cập Nhật Code Sử Dụng --- ## 📝 Code Migration Examples ### Example 1: Basic Proxy Request #### ProxyPool (gRPC) ```csharp using Icomm.ResourcePool.Abstractions; using Icomm.ResourcePool.Abstractions.Requests; using Icomm.ResourcePool.Abstractions.Responses; using MagicOnion.Client; using Grpc.Net.Client; var channel = GrpcChannel.ForAddress("http://10.9.3.70:31287"); var client = MagicOnionClient.Create(channel); var request = new ProxyRequest { AccessToken = "your-access-token" }; var response = await client.GetProxy(request); var proxy = response.Proxy; // Use proxy var handler = new HttpClientHandler { Proxy = new WebProxy($"{proxy.Host}:{proxy.Port}") { Credentials = new NetworkCredential(proxy.AuthUsername, proxy.AuthPassword) } }; var httpClient = new HttpClient(handler); ``` #### SmartPool ```csharp using Icomm.SmartPool.Proxy; using Icomm.SmartPool.Abstractions.Requests; using System.Net; public class MyService { private readonly ISmartPoolClient _smartPoolClient; public MyService(ISmartPoolClient smartPoolClient) { _smartPoolClient = smartPoolClient; } public async Task MakeRequestAsync() { // Get proxy as IWebProxy (ready to use) var request = new GetProxyRequest { access_token = "your-access-token" }; var proxy = await _smartPoolClient.GetProxyAsync(request); if (proxy != null) { var handler = new HttpClientHandler { Proxy = proxy }; var httpClient = new HttpClient(handler); // Use httpClient... } } } ``` **Key Changes:** - ✅ Không cần tự setup gRPC channel - ✅ Method `GetProxyAsync()` trả về `IWebProxy` sẵn sàng sử dụng - ✅ Field names: `access_token` thay vì `AccessToken` --- ### Example 2: Proxy Request với Filters #### ProxyPool (HTTP REST API) ```csharp using RestSharp; using Icomm.ResourcePool.Abstractions.Requests; using Icomm.ResourcePool.Abstractions.Responses; var client = new RestClient("http://10.9.3.70:31249"); var request = new RestRequest("/api/resource-pool/v1/ProxyPool/get-v2", Method.Post); request.AddJsonBody(new ProxyRequestByFeature { AccessToken = "your-access-token", Type = "httpv6", Strategy = "least_delay", TargetDomain = "facebook.com", Country = "VN" }); var response = await client.ExecuteAsync(request); var proxy = response.Data.Proxy; var proxyObj = new WebProxy($"{proxy.Host}:{proxy.Port}") { Credentials = new NetworkCredential(proxy.AuthUsername, proxy.AuthPassword) }; ``` #### SmartPool ```csharp using Icomm.SmartPool.Proxy; using Icomm.SmartPool.Abstractions.Requests; var request = new GetProxyRequest { access_token = "your-access-token", strategy = "least_delay", target_domain = "facebook.com", ip_version = "v6", protocol = "http", country = "VN" }; var proxy = await _smartPoolClient.GetProxyAsync(request); if (proxy != null) { var handler = new HttpClientHandler { Proxy = proxy }; var httpClient = new HttpClient(handler); // Use httpClient... } ``` **Key Changes:** - ✅ Không cần HTTP client setup - ✅ Field names: `ip_version`, `protocol` thay vì `Type` - ✅ Strategy names: `least_delay` thay vì `least_delay` (giống nhau) - ✅ `GetProxyAsync()` trả về `IWebProxy` sẵn sàng --- ### Example 3: Get Raw Proxy Information #### ProxyPool ```csharp var response = await client.GetProxyV2(new ProxyRequestByFeature { AccessToken = "your-access-token", Type = "httpv6", Strategy = "random", Country = "US" }); var proxy = response.Proxy; Console.WriteLine($"Proxy: {proxy.Host}:{proxy.Port}"); Console.WriteLine($"Country: {proxy.Country}"); Console.WriteLine($"Auth: {proxy.AuthUsername}:{proxy.AuthPassword}"); ``` #### SmartPool ```csharp var request = new GetProxyRequest { access_token = "your-access-token", strategy = "random", ip_version = "v6", protocol = "http", country = "US" }; var proxyServer = await _smartPoolClient.GetRawProxyAsync(request); if (proxyServer != null) { Console.WriteLine($"Proxy: {proxyServer.host}:{proxyServer.port}"); Console.WriteLine($"Country: {proxyServer.country}"); Console.WriteLine($"Auth: {proxyServer.auth_username}:{proxyServer.auth_password}"); } ``` **Key Changes:** - ✅ Method: `GetRawProxyAsync()` thay vì `GetProxyV2()` - ✅ Field names: `host`, `port`, `country`, `auth_username`, `auth_password` (snake_case) --- ### Example 4: Log Proxy Usage #### ProxyPool ```csharp var logRequest = new ProxyLogRequest { AccessToken = "your-access-token", ProxyId = proxy.Id, StatusCode = 200, ResponseTimeMs = 450 }; var logClient = new RestClient("http://10.9.3.70:31249"); var logRestRequest = new RestRequest("/api/resource-pool/v1/ProxyPool/used", Method.Post); logRestRequest.AddJsonBody(logRequest); await logClient.ExecuteAsync(logRestRequest); ``` #### SmartPool ```csharp var logRequest = new ProxyUsageLogRequest { access_token = "your-access-token", proxy_id = proxyServer.id, target_domain = "facebook.com", status_code = 200, response_time_ms = 450 }; // Synchronous logging await _smartPoolClient.LogProxyUsageAsync(logRequest); // Or fire-and-forget (non-blocking) _client.QueueLogProxyUsage(logRequest); ``` **Key Changes:** - ✅ Request type: `ProxyUsageLogRequest` thay vì `ProxyLogRequest` - ✅ Field names: `proxy_id`, `status_code`, `response_time_ms` (snake_case) - ✅ Có thêm `target_domain` field (required) - ✅ Hỗ trợ fire-and-forget và batch logging --- ### Example 5: Alternative Strategy (Find Similar Proxy) #### ProxyPool ```csharp var request = new ProxyRequestByFeature { AccessToken = "your-access-token", Strategy = "least_used", RefererProxy = new ProxyServer { Id = 123 }, Type = "httpv6", Country = "VN" }; var response = await client.GetProxyV2(request); var alternativeProxy = response.Proxy; ``` #### SmartPool ```csharp var request = new GetProxyRequest { access_token = "your-access-token", strategy = "alternative", referer_proxy = new SmartProxyServer { id = 123 }, ip_version = "v6", protocol = "http", country = "VN" }; var alternativeProxy = await _smartPoolClient.GetRawProxyAsync(request); ``` **Key Changes:** - ✅ Strategy: `alternative` thay vì `least_used` - ✅ Field: `referer_proxy.id` thay vì `RefererProxy.Id` --- ## 🔀 Field Name Mapping | ProxyPool (PascalCase) | SmartPool (snake_case) | |------------------------|------------------------| | `AccessToken` | `access_token` | | `Host` | `host` | | `Port` | `port` | | `AuthUsername` | `auth_username` | | `AuthPassword` | `auth_password` | | `Type` | `protocol` (và `ip_version`) | | `Country` | `country` | | `TargetDomain` | `target_domain` | | `Strategy` | `strategy` | | `RefererProxy` | `referer_proxy` | | `ProxyId` | `proxy_id` | | `StatusCode` | `status_code` | | `ResponseTimeMs` | `response_time_ms` | --- ## 🎯 Strategy Mapping | ProxyPool Strategy | SmartPool Strategy | Notes | |-------------------|-------------------|-------| | `random` | `random` | Giống nhau | | `round_robin` | `round_robin` | Giống nhau (default trong SmartPool) | | `least_delay` | `least_delay` | Giống nhau | | `least_used` | `alternative` | SmartPool dùng `alternative` với `referer_proxy` | | `least_response_time` | `least_delay` | Tương đương | | N/A | `adaptive_ranking` | Mới trong SmartPool | --- ## 🚨 Breaking Changes ### 1. Port Numbers - **ProxyPool**: 31287 (gRPC), 31249 (HTTP) - **SmartPool**: 5001 (gRPC), 5000 (HTTP) ### 2. API Endpoints - **ProxyPool**: `/api/resource-pool/v1/ProxyPool/*` - **SmartPool**: `/api/smart-pool/v1/SmartProxy/*` ### 3. Request/Response Types - **ProxyPool**: `ProxyRequest`, `ProxyRequestByFeature`, `ProxyResponse`, `ProxyServer` - **SmartPool**: `GetProxyRequest`, `SmartProxyResponse`, `SmartProxyServer` ### 4. Field Naming Convention - **ProxyPool**: PascalCase - **SmartPool**: snake_case ### 5. Protocol Field - **ProxyPool**: `Type` = `"http"`, `"httpv6"`, `"socks"` - **SmartPool**: `protocol` = `"http"`, `"socks5"` + `ip_version` = `"v4"`, `"v6"` --- ## ✅ Migration Checklist - [ ] Cài đặt NuGet package `Icomm.SmartPool.Proxy` - [ ] Cập nhật `appsettings.json` với SmartPool configuration - [ ] Thay thế service registration từ manual gRPC/HTTP setup sang `AddSmartPoolClient()` - [ ] Cập nhật dependency injection: inject `ISmartPoolClient` thay vì tự tạo client - [ ] Thay thế tất cả `ProxyRequest` → `GetProxyRequest` - [ ] Thay thế tất cả `ProxyRequestByFeature` → `GetProxyRequest` - [ ] Cập nhật field names từ PascalCase sang snake_case - [ ] Cập nhật strategy names (nếu có `least_used` → `alternative`) - [ ] Cập nhật `Type` field → `protocol` + `ip_version` - [ ] Thay thế `GetProxy()` / `GetProxyV2()` → `GetProxyAsync()` / `GetRawProxyAsync()` - [ ] Cập nhật proxy usage logging: `ProxyLogRequest` → `ProxyUsageLogRequest` - [ ] Cập nhật port numbers trong configuration - [ ] Test tất cả proxy requests - [ ] Test error handling với SmartPool exceptions - [ ] Cập nhật unit tests --- ## 🎁 Benefits After Migration ### 1. Performance Improvements - **Connection Pooling**: Giảm latency reconnect từ ~50-100ms xuống ~5ms - **Client-side Caching**: Giảm network calls ~90% khi cache hit - **Batch Logging**: Giảm N network calls → 1 call - **Response Compression**: Giảm payload size ~30-50% ### 2. Better Developer Experience - ✅ Typed exceptions với error codes - ✅ Try methods (`TryGetProxyAsync()`) không throw exceptions - ✅ Fire-and-forget logging (non-blocking) - ✅ Health check method (`PingAsync()`) ### 3. Advanced Features - ✅ `adaptive_ranking` strategy (mới) - ✅ `alternative` strategy với referer proxy - ✅ Client-side caching tự động - ✅ Batch logging tự động --- ## 📚 Additional Resources - [SmartPool SDK Documentation](./docs/src/Icomm.SmartPool.Proxy/README.md) - [SmartPool API Documentation](./docs/src/Icomm.API.SmartPool/README.md) - [SmartPool Quick Reference](./docs/src/Icomm.SmartPool.Proxy/QUICK_REFERENCE.md) --- ## 💡 Tips & Best Practices ### 1. Gradual Migration - Có thể migrate từng phần, không cần migrate toàn bộ cùng lúc - Có thể chạy song song ProxyPool và SmartPool trong giai đoạn transition ### 2. Error Handling ```csharp using Icomm.SmartPool.Proxy.Exceptions; try { var proxy = await _smartPoolClient.GetRawProxyAsync(request); } catch (AccessTokenRequiredException) { // Handle missing access token } catch (NoAvailableProxiesException ex) { // Handle no proxies available // Retry with different token or wait } catch (NoMatchingProxiesException) { // Handle no matching proxies // Relax filters or use different strategy } catch (SmartPoolException ex) { // Handle other SmartPool errors _logger.LogError(ex, "SmartPool error: {ErrorCode}", ex.ErrorCode); } ``` ### 3. Use Try Methods for Silent Failures ```csharp // Instead of try-catch, use Try methods var proxy = await _smartPoolClient.TryGetRawProxyAsync(request); if (proxy == null) { // Fallback logic return; } // Use proxy... ``` ### 4. Enable Client Caching for Better Performance ```json { "SmartPool": { "EnableClientCache": true, "ClientCacheDurationSeconds": 30 } } ``` ### 5. Use Batch Logging for High Throughput ```json { "SmartPool": { "EnableBatchLogging": true, "LogBatchSize": 50, "LogBatchFlushIntervalMs": 5000, "EnableFireAndForgetLogging": true } } ``` --- ## ❓ FAQ ### Q: Có thể dùng cả ProxyPool và SmartPool cùng lúc không? **A:** Có, nhưng không khuyến nghị. Nên migrate hoàn toàn sang SmartPool. ### Q: SmartPool có backward compatible với ProxyPool không? **A:** Không, SmartPool là hệ thống mới hoàn toàn với API và data model khác. ### Q: Làm sao migrate nếu đang dùng HTTP REST API? **A:** Có thể tiếp tục dùng HTTP REST API với SmartPool, nhưng khuyến nghị dùng SDK client để có nhiều tính năng tối ưu. ### Q: Có cần thay đổi access token không? **A:** Không, nhưng cần đảm bảo access token có mapping trong SmartPool system. ### Q: Performance có cải thiện bao nhiêu? **A:** Tùy use case, thường cải thiện 30-50% nhờ connection pooling, caching, và batch logging. --- ## 📞 Support Nếu gặp vấn đề trong quá trình migration, vui lòng: 1. Kiểm tra [SmartPool Documentation](./docs/src/Icomm.SmartPool.Proxy/README.md) 2. Kiểm tra [Troubleshooting Guide](./docs/src/Icomm.API.SmartPool/README.md#troubleshooting) 3. Liên hệ team phát triển --- **Last Updated**: 2026-01-23