{"record":{"id":"fa1ec8c5f189c496","repo":"egametang/ET","slug":"service-discovery-proxy-retryable-service-call-err","errorCode":null,"errorMessage":"service discovery proxy retryable service call error request: {requestName} sceneType: {sceneTypeName} error: {error} message: {message}","messagePattern":"service discovery proxy retryable service call error request: (.+?) sceneType: (.+?) error: (.+?) message: (.+?)","errorType":"exception","errorClass":"RpcException","httpStatus":null,"severity":"error","filePath":"Packages/cn.etetet.servicediscovery/Scripts/Hotfix/Server/ServiceDiscoveryProxySystem.cs","lineNumber":370,"sourceCode":"                    if (messageSender == null)\n                    {\n                        throw new Exception($\"service discovery proxy message sender is null, request: {requestName} scene: {self.Root().Name}\");\n                    }\n\n                    IResponse rawResponse = await messageSender.Call(actorId, request, needException);\n                    if (rawResponse is not T response)\n                    {\n                        (rawResponse as MessageObject)?.Dispose();\n                        throw new Exception(\n                            $\"service discovery proxy service response type mismatch request: {requestName}, actual: {rawResponse?.GetType().Name}\");\n                    }\n\n                    if (ShouldRetryServiceCallError(response.Error))\n                    {\n                        int error = response.Error;\n                        string message = response.Message;\n                        (response as MessageObject)?.Dispose();\n                        throw new RpcException(error,\n                            $\"service discovery proxy retryable service call error request: {requestName} sceneType: {sceneTypeName} error: {error} message: {message}\");\n                    }\n\n                    if (throwResponseError && response.Error != ErrorCode.ERR_Success)\n                    {\n                        int error = response.Error;\n                        string message = response.Message;\n                        (response as MessageObject)?.Dispose();\n                        throw new RpcException(error,\n                            $\"service discovery proxy service call error request: {requestName} sceneType: {sceneTypeName} error: {error} message: {message}\");\n                    }\n\n                    return response;\n                }\n                catch (RpcException rpcException)\n                {\n                    ++retryCount;\n                    self = selfRef;","sourceCodeStart":352,"sourceCodeEnd":388,"githubUrl":"https://github.com/egametang/ET/blob/5cab01f7a8bee5f49f4781eebe9e2b1c6d7ebe0f/Packages/cn.etetet.servicediscovery/Scripts/Hotfix/Server/ServiceDiscoveryProxySystem.cs#L352-L388","documentation":"RpcException thrown at line 370 in ServiceDiscoveryProxy.CallBySceneTypeAsync: the resolved target service returned a response whose Error matches ShouldRetryServiceCallError (a retryable failure). The proxy disposes the response and throws so the outer catch increments retryCount and retries (up to ServiceResolveRetryTimes) with WaitResolveRetryDelayAsync. If retries are exhausted the same RpcException propagates.","triggerScenarios":"CallBySceneTypeAsync calls a service whose response carries a retryable error code (ShouldRetryServiceCallError returns true — includes ShouldTriggerFailover codes like ERR_NotFoundActor, ERR_RpcFail, ERR_MessageTimeout, follower/master-unavailable). The proxy retries; if the service keeps failing, this exception surfaces.","commonSituations":"The target service instance is restarting (ERR_NotFoundActor); the target is overloaded (ERR_MessageTimeout); a failover-eligible error on the target that does not resolve within the retry budget; route-keyed call hitting a stale cached ActorId.","solutions":["Ensure the target service for the sceneType is healthy and registered so retry attempts succeed.","Verify the cached ActorId for the service is fresh (re-subscribe/re-resolve if stale).","Increase ServiceResolveRetryTimes only if the failure is genuinely transient; otherwise fix the target.","Check whether routeKey is correct and hashes to a valid instance."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Ensure the target service is registered/known before calling.\nif (proxy.GetBySceneType(sceneType).Count == 0)\n{\n    Log.Warning($\"no cached service for sceneType {sceneType}; call will retry/fail\");\n    return;\n}","typeGuard":null,"tryCatchPattern":"catch (RpcException e) when (ServiceDiscoveryErrorHelper.ShouldTriggerFailover(e.Error))\n{\n    // retryable; the proxy already retries up to ServiceResolveRetryTimes.\n    // If it propagates here, escalate or circuit-break.\n}","preventionTips":["Keep target service instances healthy and registered.","Refresh stale cached ActorIds via re-subscribe.","Validate routeKey maps to a live instance."],"tags":["csharp","et-framework","service-discovery","rpc","proxy","retry","network","load-balancing"],"backgroundTag":null,"analyzedSha":"5cab01f7a8bee5f49f4781eebe9e2b1c6d7ebe0f","analyzedAt":"2026-08-13T21:10:40.377Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}