Skip to content

Commit 997c985

Browse files
committed
fix secondary list are not respected
1 parent bf5edbe commit 997c985

2 files changed

Lines changed: 100 additions & 37 deletions

File tree

lib/AutoClusterFailover.cc

Lines changed: 62 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -258,30 +258,36 @@ class AutoClusterFailoverImpl : public std::enable_shared_from_this<AutoClusterF
258258
onServiceInfoUpdate_(current());
259259
}
260260

261-
void probeSecondaryFrom(size_t index, CompletionCallback done) {
261+
void probeSecondaryFrom(size_t index, const ServiceInfo* excludedServiceInfo, ProbeCallback callback) {
262262
if (index >= config_.secondary.size()) {
263-
done();
263+
callback(false);
264+
return;
265+
}
266+
267+
if (&config_.secondary[index] == excludedServiceInfo) {
268+
probeSecondaryFrom(index + 1, excludedServiceInfo, std::move(callback));
264269
return;
265270
}
266271

267272
auto weakSelf = weak_from_this();
268-
probeAvailableAsync(config_.secondary[index],
269-
[weakSelf, index, done = std::move(done)](bool available) mutable {
270-
auto self = weakSelf.lock();
271-
if (!self) {
272-
return;
273-
}
274-
275-
LOG_DEBUG("Detected secondary " << self->config_.secondary[index].serviceUrl()
276-
<< " availability: " << available);
277-
if (available) {
278-
self->switchTo(&self->config_.secondary[index]);
279-
done();
280-
return;
281-
}
282-
283-
self->probeSecondaryFrom(index + 1, std::move(done));
284-
});
273+
probeAvailableAsync(
274+
config_.secondary[index],
275+
[weakSelf, index, excludedServiceInfo, callback = std::move(callback)](bool available) mutable {
276+
auto self = weakSelf.lock();
277+
if (!self) {
278+
return;
279+
}
280+
281+
LOG_DEBUG("Detected secondary " << self->config_.secondary[index].serviceUrl()
282+
<< " availability: " << available);
283+
if (available) {
284+
self->switchTo(&self->config_.secondary[index]);
285+
callback(true);
286+
return;
287+
}
288+
289+
self->probeSecondaryFrom(index + 1, excludedServiceInfo, std::move(callback));
290+
});
285291
}
286292

287293
void checkAndFailoverToSecondaryAsync(CompletionCallback done) {
@@ -305,10 +311,45 @@ class AutoClusterFailoverImpl : public std::enable_shared_from_this<AutoClusterF
305311
return;
306312
}
307313

308-
self->probeSecondaryFrom(0, std::move(done));
314+
self->probeSecondaryFrom(0, nullptr, [done = std::move(done)](bool) mutable { done(); });
309315
});
310316
}
311317

318+
void failoverFromUnavailableSecondaryAsync(CompletionCallback done) {
319+
auto weakSelf = weak_from_this();
320+
probeAvailableAsync(
321+
config_.primary, [weakSelf, done = std::move(done)](bool primaryAvailable) mutable {
322+
auto self = weakSelf.lock();
323+
if (!self) {
324+
return;
325+
}
326+
327+
LOG_DEBUG("Detected primary while secondary is unavailable "
328+
<< self->config_.primary.serviceUrl() << " availability: " << primaryAvailable);
329+
if (primaryAvailable) {
330+
self->switchTo(&self->config_.primary);
331+
done();
332+
return;
333+
}
334+
335+
self->probeSecondaryFrom(
336+
0, self->currentServiceInfo_,
337+
[weakSelf, done = std::move(done)](bool switchedToAnotherSecondary) mutable {
338+
auto self = weakSelf.lock();
339+
if (!self) {
340+
return;
341+
}
342+
343+
if (switchedToAnotherSecondary) {
344+
done();
345+
return;
346+
}
347+
348+
self->checkSwitchBackToPrimaryAsync(std::move(done), false);
349+
});
350+
});
351+
}
352+
312353
void checkSwitchBackToPrimaryAsync(CompletionCallback done, std::optional<bool> primaryAvailableHint) {
313354
auto handlePrimaryAvailable = [weakSelf = weak_from_this(),
314355
done = std::move(done)](bool primaryAvailable) mutable {
@@ -358,23 +399,7 @@ class AutoClusterFailoverImpl : public std::enable_shared_from_this<AutoClusterF
358399
return;
359400
}
360401

361-
self->probeAvailableAsync(
362-
self->config_.primary, [weakSelf, done = std::move(done)](bool primaryAvailable) mutable {
363-
auto self = weakSelf.lock();
364-
if (!self) {
365-
return;
366-
}
367-
368-
LOG_DEBUG("Detected primary while secondary is unavailable "
369-
<< self->config_.primary.serviceUrl() << " availability: " << primaryAvailable);
370-
if (primaryAvailable) {
371-
self->switchTo(&self->config_.primary);
372-
done();
373-
return;
374-
}
375-
376-
self->checkSwitchBackToPrimaryAsync(std::move(done), false);
377-
});
402+
self->failoverFromUnavailableSecondaryAsync(std::move(done));
378403
});
379404
}
380405
};

tests/ServiceInfoProviderTest.cc

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,44 @@ TEST(AutoClusterFailoverTest, testSwitchBackToPrimaryAfterRecoveryDelay) {
273273
ASSERT_EQ(updates[2], primaryUrl);
274274
}
275275

276+
TEST(AutoClusterFailoverTest, testFailoverToAnotherSecondaryWhenCurrentSecondaryIsUnavailable) {
277+
ProbeTcpServer primary;
278+
const auto primaryUrl = primary.getServiceUrl();
279+
primary.stop();
280+
281+
ProbeTcpServer firstSecondary;
282+
const auto firstSecondaryUrl = firstSecondary.getServiceUrl();
283+
284+
ProbeTcpServer secondSecondary;
285+
const auto secondSecondaryUrl = secondSecondary.getServiceUrl();
286+
287+
ServiceUrlObserver observer;
288+
AutoClusterFailover provider =
289+
AutoClusterFailover::Builder(ServiceInfo(primaryUrl),
290+
{ServiceInfo(firstSecondaryUrl), ServiceInfo(secondSecondaryUrl)})
291+
.withCheckInterval(20ms)
292+
.withFailoverThreshold(4)
293+
.withSwitchBackThreshold(6)
294+
.build();
295+
296+
observer.onUpdate(provider.initialServiceInfo());
297+
provider.initialize([&observer](const ServiceInfo &serviceInfo) { observer.onUpdate(serviceInfo); });
298+
299+
ASSERT_TRUE(
300+
waitUntil(2s, [&observer, &firstSecondaryUrl] { return observer.last() == firstSecondaryUrl; }));
301+
302+
firstSecondary.stop();
303+
304+
ASSERT_TRUE(
305+
waitUntil(2s, [&observer, &secondSecondaryUrl] { return observer.last() == secondSecondaryUrl; }));
306+
307+
const auto updates = observer.snapshot();
308+
ASSERT_EQ(updates.size(), 3u);
309+
ASSERT_EQ(updates[0], primaryUrl);
310+
ASSERT_EQ(updates[1], firstSecondaryUrl);
311+
ASSERT_EQ(updates[2], secondSecondaryUrl);
312+
}
313+
276314
TEST(ServiceInfoProviderTest, testSwitchCluster) {
277315
extern std::string getToken(); // from tests/AuthTokenTest.cc
278316
// Access "private/auth" namespace in cluster 1

0 commit comments

Comments
 (0)