Skip to content

Commit c9ec2fe

Browse files
committed
f
1 parent 574e1a8 commit c9ec2fe

File tree

1 file changed

+33
-14
lines changed

1 file changed

+33
-14
lines changed

libs/backend-apisix/src/operator.ts

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@ import {
66
Subject,
77
catchError,
88
concatMap,
9+
delay,
910
from,
1011
map,
1112
mergeMap,
1213
of,
1314
reduce,
15+
retry,
1416
tap,
1517
throwError,
1618
} from 'rxjs';
@@ -102,38 +104,55 @@ export class Operator extends ADCSDK.backend.BackendEventSource {
102104
);
103105
}
104106

107+
private deleteUpstreamWithRetry(upstreamId: string) {
108+
// Delete upstream with retry on race condition
109+
return from(
110+
this.client.request({
111+
url: `/apisix/admin/upstreams/${upstreamId}`,
112+
method: 'DELETE',
113+
}),
114+
).pipe(
115+
retry({
116+
count: 3,
117+
delay: (error: Error | AxiosError, retryCount: number) => {
118+
// Only retry if upstream deletion fails due to "still using" race condition
119+
if (
120+
axios.isAxiosError(error) &&
121+
error.response?.data?.error_msg?.includes('is still using it')
122+
) {
123+
// Exponential backoff: 100ms, 200ms, 400ms
124+
const delayMs = 100 * Math.pow(2, retryCount - 1);
125+
return of(null).pipe(delay(delayMs));
126+
}
127+
// Don't retry other errors
128+
return throwError(() => error);
129+
},
130+
}),
131+
);
132+
}
133+
105134
private deleteServiceWithUpstream(event: ADCSDK.Event, servicePath: string) {
106-
// Delete service first, then upstream
135+
// Delete service first, then upstream with retry
107136
return from(
108137
this.client.request({
109138
url: servicePath,
110139
method: 'DELETE',
111140
}),
112141
).pipe(
113-
concatMap(() =>
114-
this.client.request({
115-
url: `/apisix/admin/upstreams/${event.resourceId}`,
116-
method: 'DELETE',
117-
}),
118-
),
142+
concatMap(() => this.deleteUpstreamWithRetry(event.resourceId)),
119143
);
120144
}
121145

122146
private deleteUpstreamThenUpdateService(event: ADCSDK.Event, data: typing.Service, servicePath: string) {
123-
// Update service first (remove upstream reference), then delete upstream
147+
// Update service first (remove upstream reference), then delete upstream with retry
124148
return from(
125149
this.client.request({
126150
url: servicePath,
127151
method: 'PUT',
128152
data,
129153
}),
130154
).pipe(
131-
concatMap(() =>
132-
this.client.request({
133-
url: `/apisix/admin/upstreams/${event.resourceId}`,
134-
method: 'DELETE',
135-
}),
136-
),
155+
concatMap(() => this.deleteUpstreamWithRetry(event.resourceId)),
137156
);
138157
}
139158

0 commit comments

Comments
 (0)