| ¶Ô±ÈÐÂÎļþ |
| | |
| | | # å¤åºåºå£è½®è¯¢åè½è®¾è®¡ææ¡£ |
| | | |
| | | **æ¥æ**: 2026-03-09 |
| | | **ä½è
**: Claude Code |
| | | **ç¶æ**: å¾
宿½ |
| | | |
| | | ## æ¦è¿° |
| | | |
| | | æ¬è®¾è®¡æ¨å¨æ¹è¿èªå¨åºåºä»»å¡çç®æ å°åé
ç½®åè½ï¼æ¯æä¸ä¸ªå··éé
ç½®å¤ä¸ªåºåºå£ï¼å¹¶éè¿è½®è¯¢ç®æ³å®ç°è´è½½åè¡¡ã |
| | | |
| | | ## éæ±èæ¯ |
| | | |
| | | å½åç³»ç»ä¸ï¼`TargetAddresses` é
ç½®éç¨ä¸å¯¹ä¸æ å°ï¼å··éåç¼ â åºåºå£å°åï¼ãä½å®é
ä¸å¡ä¸ï¼ä¸ä¸ªå··éå¯è½æå¤ä¸ªåºåºå£ï¼éè¦æ¯æï¼ |
| | | |
| | | 1. **ä¸å¯¹å¤å
³ç³»**ï¼ä¸ä¸ªå··éå¯ä»¥é
ç½®å¤ä¸ªåºåºå£ |
| | | 2. **è´è½½åè¡¡**ï¼éè¿è½®è¯¢ç®æ³éæ©åºåºå£ï¼é¿å
åç¹åå |
| | | 3. **ååå
¼å®¹**ï¼ä¿æå¯¹ååºå£é
ç½®çæ¯æ |
| | | |
| | | ## ææ¯æ¹æ¡ |
| | | |
| | | ### æ¶æéæ© |
| | | |
| | | éç¨ **å
å轮询计æ°å¨ + ç¬ç«æå¡ç±»** çæ¨¡å¼ï¼ |
| | | |
| | | 1. **RoundRobinService**ï¼ç¬ç«ç轮询æå¡ç±»ï¼ç®¡ç轮询计æ°å¨ |
| | | 2. **é
置模ååæ´**ï¼`Dictionary<string, string>` â `Dictionary<string, List<string>>` |
| | | 3. **线ç¨å®å
¨**ï¼ä½¿ç¨ `ConcurrentDictionary` ä¿è¯å¤çº¿ç¨å®å
¨ |
| | | |
| | | ### æ ¸å¿è®¾è®¡ |
| | | |
| | | #### 1. é
ç½®æ ¼å¼åæ´ |
| | | |
| | | **appsettings.json:** |
| | | ```json |
| | | { |
| | | "AutoOutboundTask": { |
| | | "TargetAddresses": { |
| | | "GW": ["10081", "10082", "10083"], |
| | | "CW": ["10080"] |
| | | } |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | **说æï¼** |
| | | - å¼ç±»åä» `string` æ¹ä¸º `string[]`ï¼JSON æ°ç»ï¼ |
| | | - æ¯æä¸ä¸ªå··éé
ç½®å¤ä¸ªåºåºå£ |
| | | - å个åºåºå£ä¹å¯ç¨æ°ç»æ ¼å¼ï¼åªæä¸ä¸ªå
ç´ ï¼ |
| | | |
| | | #### 2. é
置模åç±» |
| | | |
| | | **AutoOutboundTaskOptions.cs:** |
| | | ```csharp |
| | | public class AutoOutboundTaskOptions |
| | | { |
| | | public bool Enable { get; set; } = true; |
| | | public int CheckIntervalSeconds { get; set; } = 300; |
| | | |
| | | public Dictionary<string, List<string>> TargetAddresses { get; set; } |
| | | = new() |
| | | { |
| | | { "GW", new List<string> { "10081" } }, |
| | | { "CW", new List<string> { "10080" } } |
| | | }; |
| | | } |
| | | ``` |
| | | |
| | | #### 3. 轮询æå¡ç±» |
| | | |
| | | **RoundRobinService.cs** (æ°å»º): |
| | | ```csharp |
| | | using System.Collections.Concurrent; |
| | | |
| | | namespace WIDESEA_Core.Core |
| | | { |
| | | /// <summary> |
| | | /// 轮询æå¡ - 线ç¨å®å
¨çå°åè½®è¯¢éæ© |
| | | /// </summary> |
| | | public class RoundRobinService |
| | | { |
| | | private readonly ConcurrentDictionary<string, int> _counters = new(); |
| | | |
| | | /// <summary> |
| | | /// è·åä¸ä¸ä¸ªå°åï¼è½®è¯¢ï¼ |
| | | /// </summary> |
| | | /// <param name="key">å··éåç¼</param> |
| | | /// <param name="addresses">å°åå表</param> |
| | | /// <returns>éä¸çå°å</returns> |
| | | public string GetNextAddress(string key, List<string> addresses) |
| | | { |
| | | if (addresses == null || addresses.Count == 0) |
| | | return "10080"; |
| | | |
| | | if (addresses.Count == 1) |
| | | return addresses[0]; |
| | | |
| | | // AddOrUpdate æ¯ååæä½ï¼çº¿ç¨å®å
¨ |
| | | int index = _counters.AddOrUpdate( |
| | | key, |
| | | 0, // 馿¬¡ä½¿ç¨ï¼ä» 0 å¼å§ |
| | | (k, old) => (old + 1) % addresses.Count // 轮询ï¼éå¢å忍¡ |
| | | ); |
| | | |
| | | return addresses[index]; |
| | | } |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | **å
³é®ç¹æ§ï¼** |
| | | - ä½¿ç¨ `ConcurrentDictionary<string, int>` å卿¯ä¸ªå··éçå½åç´¢å¼ |
| | | - `AddOrUpdate` æ¹æ³ä¿è¯ååæ§ï¼æ éé¢å¤é |
| | | - 模è¿ç®å®ç°å¾ªç¯è½®è¯¢ |
| | | - 线ç¨å®å
¨ï¼æ¯æåå°æå¡çå¹¶åè°ç¨ |
| | | |
| | | #### 4. TaskService æ¹æ³ä¿®æ¹ |
| | | |
| | | **DetermineTargetAddress æ¹æ³:** |
| | | ```csharp |
| | | private string DetermineTargetAddress( |
| | | string roadway, |
| | | Dictionary<string, List<string>> addressMap) |
| | | { |
| | | if (string.IsNullOrWhiteSpace(roadway)) |
| | | return "10080"; |
| | | |
| | | // æ¥æ¾å¹é
çå··éåç¼ |
| | | string matchedPrefix = null; |
| | | foreach (var kvp in addressMap) |
| | | { |
| | | if (roadway.Contains(kvp.Key)) |
| | | { |
| | | matchedPrefix = kvp.Key; |
| | | break; |
| | | } |
| | | } |
| | | |
| | | if (matchedPrefix == null) |
| | | return "10080"; |
| | | |
| | | var addresses = addressMap[matchedPrefix]; |
| | | if (addresses == null || addresses.Count == 0) |
| | | return "10080"; |
| | | |
| | | // å个å°åï¼ç´æ¥è¿å |
| | | if (addresses.Count == 1) |
| | | return addresses[0]; |
| | | |
| | | // å¤ä¸ªå°åï¼ä½¿ç¨è½®è¯¢ |
| | | return _roundRobinService.GetNextAddress(matchedPrefix, addresses); |
| | | } |
| | | ``` |
| | | |
| | | **ä¾èµæ³¨å
¥:** |
| | | ```csharp |
| | | public class TaskService |
| | | { |
| | | private readonly RoundRobinService _roundRobinService; |
| | | |
| | | public TaskService( |
| | | // ... å
¶ä»ä¾èµ |
| | | RoundRobinService roundRobinService) |
| | | { |
| | | // ... å
¶ä»èµå¼ |
| | | _roundRobinService = roundRobinService; |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | #### 5. æå¡æ³¨å |
| | | |
| | | **Program.cs:** |
| | | ```csharp |
| | | // 注å为åä¾ï¼ä¿è¯å
¨å±å
±äº«è®¡æ°å¨ |
| | | builder.Services.AddSingleton<RoundRobinService>(); |
| | | ``` |
| | | |
| | | ## æ°æ®æµç¨ |
| | | |
| | | ```mermaid |
| | | graph TD |
| | | A[å建åºåºä»»å¡] --> B[è·ååºåå··éä¿¡æ¯] |
| | | B --> C[æ¥æ¾å¹é
çå··éåç¼] |
| | | C --> D{å°åå表æ°é} |
| | | D -->|0个| E[è¿åé»è®¤å°å 10080] |
| | | D -->|1个| F[ç´æ¥è¿å该å°å] |
| | | D -->|å¤ä¸ª| G[è°ç¨ RoundRobinService] |
| | | G --> H[æ¥è¯¢/æ´æ°è®¡æ°å¨] |
| | | H --> I[è¿å addresses counter % count] |
| | | I --> J[å建任å¡] |
| | | F --> J |
| | | E --> J |
| | | ``` |
| | | |
| | | ## è½®è¯¢ç¤ºä¾ |
| | | |
| | | **é
ç½®:** |
| | | ```json |
| | | { |
| | | "TargetAddresses": { |
| | | "GW": ["10081", "10082", "10083"] |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | **è°ç¨åºå:** |
| | | | æ¬¡æ° | 计æ°å¨å¼ | è¿åå°å | |
| | | |------|---------|---------| |
| | | | 1 | 0 | 10081 | |
| | | | 2 | 1 | 10082 | |
| | | | 3 | 2 | 10083 | |
| | | | 4 | 0 | 10081 | |
| | | | 5 | 1 | 10082 | |
| | | | ... | ... | ... | |
| | | |
| | | ## é误å¤ç |
| | | |
| | | 1. **é
ç½®é误**ï¼ |
| | | - å°åå表为空 â è¿åé»è®¤å°å "10080" |
| | | - å··éä¸å¹é
ä»»ä½åç¼ â è¿åé»è®¤å°å "10080" |
| | | |
| | | 2. **å¹¶åå®å
¨**ï¼ |
| | | - ä½¿ç¨ `ConcurrentDictionary` ä¿è¯çº¿ç¨å®å
¨ |
| | | - `AddOrUpdate` æ¯ååæä½ |
| | | |
| | | 3. **åºç¨éå¯**ï¼ |
| | | - 轮询ä½ç½®é置为 0 |
| | | - 坿¥åçæè¡¡ï¼ç®åå®ç°ï¼ |
| | | |
| | | ## ååå
¼å®¹æ§ |
| | | |
| | | ### æ§é
ç½®æ ¼å¼ |
| | | ```json |
| | | { |
| | | "TargetAddresses": { |
| | | "GW": "10081", |
| | | "CW": "10080" |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | ### æ°é
ç½®æ ¼å¼ |
| | | ```json |
| | | { |
| | | "TargetAddresses": { |
| | | "GW": ["10081"], |
| | | "CW": ["10080"] |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | **å
¼å®¹æ§å¤çï¼** |
| | | - JSON é
ç½®ç»å®ä¼èªå¨å¤çä¸¤ç§æ ¼å¼ |
| | | - å个å符串ä¼è¢«è§£æä¸ºåå
ç´ æ°ç» |
| | | - ç°æé
ç½®æ éä¿®æ¹å³å¯å·¥ä½ |
| | | |
| | | ## æ§è½å½±å |
| | | |
| | | 1. **å
åå¼é**ï¼æ¯ä¸ªå··éåç¼ä¸ä¸ªæ´æ°è®¡æ°å¨ï¼çº¦ 50 åèï¼ |
| | | 2. **CPU å¼é**ï¼æ¨¡è¿ç®ååå
¸æ¥æ¾ï¼O(1) å¤æåº¦ |
| | | 3. **线ç¨å®å
¨**ï¼æ é设计ï¼`ConcurrentDictionary` 使ç¨ä¼åç忥æºå¶ |
| | | |
| | | ## æµè¯è®¡å |
| | | |
| | | ### åå
æµè¯ |
| | | 1. `RoundRobinService.GetNextAddress` 轮询é»è¾ |
| | | 2. å个å°åç´æ¥è¿å |
| | | 3. å¤ä¸ªå°å轮询è¿å |
| | | 4. å¹¶åè°ç¨æµè¯ |
| | | |
| | | ### éææµè¯ |
| | | 1. ä¿®æ¹ appsettings.json 为å¤åºå£é
ç½® |
| | | 2. å建å¤ä¸ªåºåºä»»å¡ |
| | | 3. éªè¯ç®æ å°å轮询åé
|
| | | 4. éªè¯æ¥å¿è®°å½ |
| | | |
| | | ### æå¨æµè¯ |
| | | ```sql |
| | | -- å夿µè¯æ°æ® |
| | | UPDATE Dt_StockInfo |
| | | SET OutboundDate = DATEADD(MINUTE, -5, GETDATE()) |
| | | WHERE PalletCode IN ('TEST001', 'TEST002', 'TEST003') |
| | | AND StockStatus = 1; |
| | | ``` |
| | | |
| | | å¯å¨åºç¨ï¼è§å¯æ¥å¿ï¼ |
| | | ``` |
| | | info: åå»ºä»»å¡ TEST001ï¼ç®æ å°å: 10081 |
| | | info: åå»ºä»»å¡ TEST002ï¼ç®æ å°å: 10082 |
| | | info: åå»ºä»»å¡ TEST003ï¼ç®æ å°å: 10083 |
| | | ``` |
| | | |
| | | ## é¨ç½²æ³¨æäºé¡¹ |
| | | |
| | | 1. **é
ç½®æ´æ°**ï¼ |
| | | - å° `TargetAddresses` çå¼ä»å符串æ¹ä¸ºæ°ç»æ ¼å¼ |
| | | - ç¡®ä¿æ¯ä¸ªæ°ç»è³å°æä¸ä¸ªå
ç´ |
| | | |
| | | 2. **ä¾èµæ³¨å
¥**ï¼ |
| | | - ç¡®ä¿ `RoundRobinService` 已注å为åä¾ |
| | | - `TaskService` æé 彿°éè¦æ³¨å
¥è¯¥æå¡ |
| | | |
| | | 3. **åæ»æ¹æ¡**ï¼ |
| | | - ä¿ç `appsettings.json` å¤ä»½ |
| | | - å¦éé®é¢å¯æ¢å¤ä¸ºååºå£é
ç½® |
| | | |
| | | ## æªæ¥æ¹è¿ |
| | | |
| | | 1. **æé轮询**ï¼æ¯æä¸ºæ¯ä¸ªå°åé
ç½®æé |
| | | 2. **å¥åº·æ£æ¥**ï¼æé¤ä¸å¯ç¨çåºåºå£ |
| | | 3. **æä¹
å**ï¼å°è½®è¯¢ä½ç½®ä¿åå° Redis/æ°æ®åº |
| | | 4. **çæ§ç»è®¡**ï¼è®°å½æ¯ä¸ªå°åçä»»å¡åé
æ°é |
| | | |
| | | ## 宿½æ¸
å |
| | | |
| | | - [ ] ä¿®æ¹ `AutoOutboundTaskOptions.TargetAddresses` ç±»å |
| | | - [ ] å建 `RoundRobinService` ç±» |
| | | - [ ] ä¿®æ¹ `TaskService.DetermineTargetAddress` æ¹æ³ |
| | | - [ ] å¨ `Program.cs` 注å `RoundRobinService` |
| | | - [ ] æ´æ° `appsettings.json` é
ç½®ç¤ºä¾ |
| | | - [ ] ç¼è¯éªè¯ |
| | | - [ ] æå¨æµè¯ |
| | | - [ ] æ´æ°è®¾è®¡ææ¡£ |