@@ -603,16 +603,20 @@ private <T extends ResourceUpdate> void handleResourceUpdate(
603603 }
604604
605605 if (invalidResources .contains (resourceName )) {
606- // The resource update is invalid. Capture the error without notifying the watchers .
606+ // The resource update is invalid (NACK). Handle as a data error .
607607 subscriber .onRejected (args .versionInfo , updateTime , errorDetail );
608- }
609-
610- if (invalidResources .contains (resourceName )) {
611- // The resource is missing. Reuse the cached resource if possible.
612- if (subscriber .data == null ) {
613- // No cached data. Notify the watchers of an invalid update.
614- subscriber .onError (Status .UNAVAILABLE .withDescription (errorDetail ), processingTracker );
608+
609+ // Handle data errors (NACKs) based on fail_on_data_errors server feature.
610+ // When xdsDataErrorHandlingEnabled is true and fail_on_data_errors is present,
611+ // delete cached data so onError will call onResourceChanged instead of onAmbientError.
612+ // When xdsDataErrorHandlingEnabled is false, use old behavior (always keep cached data).
613+ if (BootstrapperImpl .xdsDataErrorHandlingEnabled && subscriber .data != null
614+ && args .serverInfo .failOnDataErrors ()) {
615+ subscriber .data = null ;
615616 }
617+ // Call onError, which will decide whether to call onResourceChanged or onAmbientError
618+ // based on whether data exists after the above deletion.
619+ subscriber .onError (Status .UNAVAILABLE .withDescription (errorDetail ), processingTracker );
616620 continue ;
617621 }
618622
@@ -866,20 +870,42 @@ void onAbsent(@Nullable ProcessingTracker processingTracker, ServerInfo serverIn
866870 return ;
867871 }
868872
869- // Ignore deletion of State of the World resources when this feature is on,
870- // and the resource is reusable.
873+ // Handle data errors (resource deletions) based on fail_on_data_errors server feature.
874+ // When xdsDataErrorHandlingEnabled is true and fail_on_data_errors is not present,
875+ // we treat deletions as ambient errors and keep using the cached resource.
876+ // When fail_on_data_errors is present, we delete the cached resource and fail.
877+ // When xdsDataErrorHandlingEnabled is false, use the old behavior (ignore_resource_deletion).
871878 boolean ignoreResourceDeletionEnabled = serverInfo .ignoreResourceDeletion ();
872- if (ignoreResourceDeletionEnabled && type .isFullStateOfTheWorld () && data != null ) {
873- if (!resourceDeletionIgnored ) {
874- logger .log (XdsLogLevel .FORCE_WARNING ,
875- "xds server {0}: ignoring deletion for resource type {1} name {2}}" ,
876- serverInfo .target (), type , resource );
877- resourceDeletionIgnored = true ;
879+ boolean failOnDataErrors = serverInfo .failOnDataErrors ();
880+ boolean xdsDataErrorHandlingEnabled = BootstrapperImpl .xdsDataErrorHandlingEnabled ;
881+
882+ if (type .isFullStateOfTheWorld () && data != null ) {
883+ // New behavior (per gRFC A88): Default is to treat deletions as ambient errors
884+ if (xdsDataErrorHandlingEnabled && !failOnDataErrors ) {
885+ if (!resourceDeletionIgnored ) {
886+ logger .log (XdsLogLevel .FORCE_WARNING ,
887+ "xds server {0}: ignoring deletion for resource type {1} name {2}}" ,
888+ serverInfo .target (), type , resource );
889+ resourceDeletionIgnored = true ;
890+ }
891+ Status deletionStatus = Status .NOT_FOUND .withDescription (
892+ "Resource " + resource + " deleted from server" );
893+ onAmbientError (deletionStatus , processingTracker );
894+ return ;
895+ }
896+ // Old behavior: Use ignore_resource_deletion server feature
897+ if (!xdsDataErrorHandlingEnabled && ignoreResourceDeletionEnabled ) {
898+ if (!resourceDeletionIgnored ) {
899+ logger .log (XdsLogLevel .FORCE_WARNING ,
900+ "xds server {0}: ignoring deletion for resource type {1} name {2}}" ,
901+ serverInfo .target (), type , resource );
902+ resourceDeletionIgnored = true ;
903+ }
904+ Status deletionStatus = Status .NOT_FOUND .withDescription (
905+ "Resource " + resource + " deleted from server" );
906+ onAmbientError (deletionStatus , processingTracker );
907+ return ;
878908 }
879- Status deletionStatus = Status .NOT_FOUND .withDescription (
880- "Resource " + resource + " deleted from server" );
881- onAmbientError (deletionStatus , processingTracker );
882- return ;
883909 }
884910
885911 logger .log (XdsLogLevel .INFO , "Conclude {0} resource {1} not exist" , type , resource );
0 commit comments