Skip to content

Commit 14fd8ef

Browse files
xds: xdsClient caches transient error for new watchers (v1.75.x backport) (#12291)
Backport of #12262 to v1.75.x. --- Fixes #11672 Co-authored-by: MV Shiva <[email protected]>
1 parent 653d076 commit 14fd8ef

File tree

2 files changed

+30
-0
lines changed

2 files changed

+30
-0
lines changed

xds/src/main/java/io/grpc/xds/client/XdsClientImpl.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -676,6 +676,8 @@ private final class ResourceSubscriber<T extends ResourceUpdate> {
676676
private ResourceMetadata metadata;
677677
@Nullable
678678
private String errorDescription;
679+
@Nullable
680+
private Status lastError;
679681

680682
ResourceSubscriber(XdsResourceType<T> type, String resource) {
681683
syncContext.throwIfNotInThisSynchronizationContext();
@@ -712,11 +714,16 @@ void addWatcher(ResourceWatcher<T> watcher, Executor watcherExecutor) {
712714
watchers.put(watcher, watcherExecutor);
713715
T savedData = data;
714716
boolean savedAbsent = absent;
717+
Status savedError = lastError;
715718
watcherExecutor.execute(() -> {
716719
if (errorDescription != null) {
717720
watcher.onError(Status.INVALID_ARGUMENT.withDescription(errorDescription));
718721
return;
719722
}
723+
if (savedError != null) {
724+
watcher.onError(savedError);
725+
return;
726+
}
720727
if (savedData != null) {
721728
notifyWatcher(watcher, savedData);
722729
} else if (savedAbsent) {
@@ -808,6 +815,7 @@ void onData(ParsedResource<T> parsedResource, String version, long updateTime,
808815
this.metadata = ResourceMetadata
809816
.newResourceMetadataAcked(parsedResource.getRawResource(), version, updateTime);
810817
absent = false;
818+
lastError = null;
811819
if (resourceDeletionIgnored) {
812820
logger.log(XdsLogLevel.FORCE_INFO, "xds server {0}: server returned new version "
813821
+ "of resource for which we previously ignored a deletion: type {1} name {2}",
@@ -857,6 +865,7 @@ void onAbsent(@Nullable ProcessingTracker processingTracker, ServerInfo serverIn
857865
if (!absent) {
858866
data = null;
859867
absent = true;
868+
lastError = null;
860869
metadata = serverInfo.resourceTimerIsTransientError()
861870
? ResourceMetadata.newResourceMetadataTimeout()
862871
: ResourceMetadata.newResourceMetadataDoesNotExist();
@@ -894,6 +903,7 @@ void onError(Status error, @Nullable ProcessingTracker tracker) {
894903
Status errorAugmented = Status.fromCode(error.getCode())
895904
.withDescription(description + "nodeID: " + bootstrapInfo.node().getId())
896905
.withCause(error.getCause());
906+
this.lastError = errorAugmented;
897907

898908
for (ResourceWatcher<T> watcher : watchers.keySet()) {
899909
if (tracker != null) {

xds/src/test/java/io/grpc/xds/GrpcXdsClientImplTestBase.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,8 @@ public long currentTimeNanos() {
285285
@Mock
286286
private ResourceWatcher<LdsUpdate> ldsResourceWatcher;
287287
@Mock
288+
private ResourceWatcher<LdsUpdate> ldsResourceWatcher2;
289+
@Mock
288290
private ResourceWatcher<RdsUpdate> rdsResourceWatcher;
289291
@Mock
290292
private ResourceWatcher<CdsUpdate> cdsResourceWatcher;
@@ -694,6 +696,24 @@ public void ldsResourceUpdated_withXdstpResourceName_withUnknownAuthority() {
694696
assertThat(resourceDiscoveryCalls.poll()).isNull();
695697
}
696698

699+
@Test
700+
public void ldsResource_onError_cachedForNewWatcher() {
701+
xdsClient.watchXdsResource(XdsListenerResource.getInstance(), LDS_RESOURCE,
702+
ldsResourceWatcher);
703+
DiscoveryRpcCall call = resourceDiscoveryCalls.poll();
704+
call.sendCompleted();
705+
verify(ldsResourceWatcher).onError(errorCaptor.capture());
706+
Status initialError = errorCaptor.getValue();
707+
xdsClient.watchXdsResource(XdsListenerResource.getInstance(), LDS_RESOURCE,
708+
ldsResourceWatcher2);
709+
ArgumentCaptor<Status> secondErrorCaptor = ArgumentCaptor.forClass(Status.class);
710+
verify(ldsResourceWatcher2).onError(secondErrorCaptor.capture());
711+
Status cachedError = secondErrorCaptor.getValue();
712+
713+
assertThat(cachedError).isEqualTo(initialError);
714+
assertThat(resourceDiscoveryCalls.poll()).isNull();
715+
}
716+
697717
@Test
698718
public void ldsResponseErrorHandling_allResourcesFailedUnpack() {
699719
DiscoveryRpcCall call = startResourceWatcher(XdsListenerResource.getInstance(), LDS_RESOURCE,

0 commit comments

Comments
 (0)