增加重试策略说明
大石头 authored at 2025-09-20 22:47:39
3.38 KiB
NewLife.Remoting
# ÖØÊÔ²ßÂÔ£¨IRetryPolicy£©Ê¹ÓÃ˵Ã÷ ±¾Îĵµ½éÉÜ `NewLife.Remoting` ÖÐÐÂÔöµÄ¿ÉÑ¡ÖØÊÔÄÜÁ¦£¬°üÀ¨ÆôÓ÷½Ê½¡¢½Ó¿ÚÔ¼¶¨ÓëʾÀý²ßÂÔ¡£ ## ¸ÅÊö - Ä¿±ê£ºÌáÉý¿Í»§¶ËÔÚ˲ʱ´íÎó£¨ÍøÂç¶¶¶¯¡¢¶ÌÔݲ»¿ÉÓõȣ©ÏµĽ¡×³ÐÔ¡£ - ĬÈÏÐÐΪ£º²»ÆôÓÃÖØÊÔ£¨±£³Ö¼ÈÓÐÓïÒ壩¡£ - ÉúЧÌõ¼þ£º`ApiClient.RetryPolicy != null` ÇÒ `ApiClient.MaxRetries > 0`¡£ - ÌØÀý£º401£¨Unauthorized£©ÈÔ²ÉÓüÈÓÐÐÐΪ¡ª¡ª´¥·¢Ò»´Î `OnLoginAsync(force=true)` ºóÔÚͬһÁ¬½ÓÉÏÖØ·¢£¬²»¼ÆÈëÖØÊÔ´ÎÊý¡£ ## ÆôÓ÷½Ê½ ```csharp var client = new ApiClient("tcp://127.0.0.1:12345") { RetryPolicy = new MyRetryPolicy(), MaxRetries = 3 // ²»º¬Ê״γ¢ÊÔ }; var result = await client.InvokeAsync<string>("Hello/Say", new { Name = "Stone" }); ``` - `RetryPolicy`£ºÊµÏÖ `IRetryPolicy`£¬ÓÃÓÚ°´Òì³£ÀàÐÍÓ뵱ǰµÚ¼¸´ÎÖØÊÔ£¬¾ö¶¨ÊÇ·ñÖØÊÔ¡¢µÈ´ý¶à¾Ã¡¢ÊÇ·ñ¸ü»»Á¬½Ó¡£ - `MaxRetries`£º×î´óÖØÊÔ´ÎÊý£¬²»º¬Ê״γ¢ÊÔ£¨0 ±íʾ½ûÓã©¡£ ## ²ßÂÔ½Ó¿Ú ```csharp public interface IRetryPolicy { bool ShouldRetry(Exception exception, int attempt, out TimeSpan delay, out bool refreshClient); } ``` - `exception`£º±¾´Îʧ°ÜµÄÒì³££¨¿É¾Ý´Ëɸѡ Transient£©¡£ - `attempt`£ºµ±Ç°ÖØÊÔÐòºÅ£¨´Ó 1 ¿ªÊ¼£¬²»º¬Ê״Σ©¡£ - `delay`£º½¨ÒéµÈ´ýʱ³¤£»`TimeSpan.Zero` ±íʾ²»µÈ´ýÁ¢¼´ÖØÊÔ¡£ - `refreshClient`£ºÊÇ·ñÔÚÖØÊÔǰ¸ü»»µ×²ãÁ¬½Ó£¨`Cluster.Return` Ö®ºóÔÙ `Cluster.Get`£©¡£ ## ʾÀý²ßÂÔ£ºÖ¸ÊýÍ豆 + Á¬½Ó¿ÉÑ¡Çл» ```csharp public sealed class MyRetryPolicy : IRetryPolicy { public bool ShouldRetry(Exception exception, int attempt, out TimeSpan delay, out bool refreshClient) { // 401 ÓÉ¿ò¼Ü²ã´¦Àí£¬²»ÔÚ²ßÂÔÄÚÖØÊÔ if (exception is ApiException aex && aex.Code == ApiCode.Unauthorized) { delay = TimeSpan.Zero; refreshClient = false; return false; } // ¶ÔÓÚ³¬Ê±/ÍøÂçÒì³£µÈ£º×î¶àÍ豆 2^attempt * 100ms£¬×î¶à 2 Ãë if (exception is TimeoutException || exception is TaskCanceledException || exception is IOException || exception is SocketException) { var ms = Math.Min(2000, (int)Math.Pow(2, attempt) * 100); delay = TimeSpan.FromMilliseconds(ms); // µÚ 2 ´Î¼°ÒÔºó³¢ÊÔÇл»Á¬½Ó refreshClient = attempt >= 2; return true; } // ÆäËüÒì³££¬²»ÖØÊÔ delay = TimeSpan.Zero; refreshClient = false; return false; } } ``` ## ÐÐΪϸ½Ú - 401 ´¦Àí£º¿ò¼Ü²¶»ñºóµ÷Óà `OnLoginAsync(force=true)`£¬ÔÙÔÚͬһÁ¬½ÓÉÏÖØ·¢Ò»´Î£¬²»¼ÆÈë `MaxRetries`¡£ - ³¬Ê±ÏûÏ¢£ºÖØÊÔ×îÖÕÈÔʧ°Ü»ò²ßÂÔδ´¥·¢Ê±£¬`TaskCanceledException` »á±»×ªÎª¶ÌÏûÏ¢£º`"[action]³¬Ê±[Timeout]È¡Ïû"`£¬ÔÚÈÕÖ¾¼¶±ð Debug ϰüº¬¸ü¶àÉÏÏÂÎÄ¡£ - Á¬½ÓÇл»£ºµ± `refreshClient=true` ʱ£¬µ±Ç°Á¬½Ó½«¹é»¹£¬ÖØÊÔÇ°ÖØÐÂ´Ó `Cluster` »ñÈ¡¡£ - È¡ÏûÖ§³Ö£º`InvokeAsync` µÄ `CancellationToken` ½«Ôڵȴý `delay` ʱ±»¹Û²ì£¬È¡Ïû»áÁ¢¼´ÖжÏÖØÊÔ²¢Å׳ö¡£ ## ½¨ÒéÓë×î¼Ñʵ¼ù - ºÏÀíµÄ `MaxRetries`£º2~3 ´Îͨ³£×ã¹»£¬±ÜÃâÖØÊԷ籩¡£ - Í˱ܲßÂÔ£ºÊ¹ÓÃÏßÐÔ/Ö¸ÊýÍ˱ܣ¬±ÜÃâÃܼ¯ÖØÊÔ¡£ - Á¬½ÓÇл»£º½öÔÚÈ·ÈÏÁ¬½Ó²ãÒì³£»òÁ¬ÐøÊ§°ÜºóÔÙÇл»¡£ - ¹Û²â£º½áºÏ `SlowTrace` ÓëÈÕÖ¾£¬ÆÀ¹ÀÖØÊԶԶ˵½¶ËºÄʱµÄÓ°Ïì¡£ ## ³£¼ûÎÊÌâ - Q£ºÆôÓÃÖØÊÔºóÊÇ·ñ»á¸Ä±äÕý³£ÒµÎñÓïÒ壿 - A£º²»»á¡£Ä¬Èϲ»ÆôÓã»ÆôÓúóÖ»¶Ô²ßÂÔÅж¨µÄÒì³£½øÐÐÓÐÏÞ´ÎÖØÊÔ¡£ - Q£ºÓëÁ¬½Ó³Ø/µ¥Á¬½ÓģʽÊÇ·ñ¼æÈÝ£¿ - A£º¼æÈÝ¡£`refreshClient` Ϊ true ʱÔÚÁ½ÖÖģʽ϶¼»á¹é»¹²¢ÖØÐ»ñÈ¡Á¬½Ó¡£ - Q£ºÊÇ·ñÌṩÄÚÖòßÂÔ£¿ - A£ººËÐĿⲻÄÚÖ㬱ÜÃâÐÐΪÕùÒ飻¿ÉÔÚÀ©Õ¹¿â»òÒµÎñ²àÌṩͨÓòßÂÔ¡£ ## ²Î¿¼ - `ApiClient.InvokeAsync<TResult>`£º¿ÉÑ¡ÖØÊÔÂß¼­Èë¿Ú¡£ - `ApiClient.OnLoginAsync(...)`£º401 µÇ¼ºóÖØ·¢µÄ¹³×Ó¡£ - `IRetryPolicy`£º×Ô¶¨ÒåÖØÊÔ²ßÂÔ½Ó¿Ú¡£