|
|
|
@ -20,10 +20,13 @@ |
|
|
|
|
|
|
|
|
|
#include <inttypes.h> |
|
|
|
|
|
|
|
|
|
#include <functional> |
|
|
|
|
#include <utility> |
|
|
|
|
#include <vector> |
|
|
|
|
|
|
|
|
|
#include "absl/status/status.h" |
|
|
|
|
#include "absl/status/statusor.h" |
|
|
|
|
#include "absl/strings/str_cat.h" |
|
|
|
|
#include "absl/strings/string_view.h" |
|
|
|
|
#include "absl/strings/strip.h" |
|
|
|
|
|
|
|
|
@ -36,6 +39,7 @@ |
|
|
|
|
#include "src/core/lib/gprpp/work_serializer.h" |
|
|
|
|
#include "src/core/lib/iomgr/exec_ctx.h" |
|
|
|
|
#include "src/core/lib/iomgr/timer.h" |
|
|
|
|
#include "src/core/lib/service_config/service_config.h" |
|
|
|
|
#include "src/core/lib/uri/uri_parser.h" |
|
|
|
|
|
|
|
|
|
namespace grpc_core { |
|
|
|
@ -69,7 +73,16 @@ void PollingResolver::StartLocked() { MaybeStartResolvingLocked(); } |
|
|
|
|
|
|
|
|
|
void PollingResolver::RequestReresolutionLocked() { |
|
|
|
|
if (request_ == nullptr) { |
|
|
|
|
MaybeStartResolvingLocked(); |
|
|
|
|
// If we're still waiting for a result-health callback from the last
|
|
|
|
|
// result we reported, don't trigger the re-resolution until we get
|
|
|
|
|
// that callback.
|
|
|
|
|
if (result_status_state_ == |
|
|
|
|
ResultStatusState::kResultHealthCallbackPending) { |
|
|
|
|
result_status_state_ = |
|
|
|
|
ResultStatusState::kReresolutionRequestedWhileCallbackWasPending; |
|
|
|
|
} else { |
|
|
|
|
MaybeStartResolvingLocked(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -126,44 +139,78 @@ void PollingResolver::OnRequestCompleteLocked(Result result) { |
|
|
|
|
} |
|
|
|
|
request_.reset(); |
|
|
|
|
if (!shutdown_) { |
|
|
|
|
if (result.service_config.ok() && result.addresses.ok()) { |
|
|
|
|
// Reset backoff state so that we start from the beginning when the
|
|
|
|
|
// next request gets triggered.
|
|
|
|
|
backoff_.Reset(); |
|
|
|
|
} else { |
|
|
|
|
if (GPR_UNLIKELY(tracer_ != nullptr && tracer_->enabled())) { |
|
|
|
|
gpr_log(GPR_INFO, |
|
|
|
|
"[polling resolver %p] resolution failed (will retry): " |
|
|
|
|
"address status \"%s\"; service config status \"%s\"", |
|
|
|
|
this, result.addresses.status().ToString().c_str(), |
|
|
|
|
result.service_config.status().ToString().c_str()); |
|
|
|
|
} |
|
|
|
|
// Set up for retry.
|
|
|
|
|
// InvalidateNow to avoid getting stuck re-initializing this timer
|
|
|
|
|
// in a loop while draining the currently-held WorkSerializer.
|
|
|
|
|
// Also see https://github.com/grpc/grpc/issues/26079.
|
|
|
|
|
ExecCtx::Get()->InvalidateNow(); |
|
|
|
|
Timestamp next_try = backoff_.NextAttemptTime(); |
|
|
|
|
Duration timeout = next_try - ExecCtx::Get()->Now(); |
|
|
|
|
GPR_ASSERT(!have_next_resolution_timer_); |
|
|
|
|
have_next_resolution_timer_ = true; |
|
|
|
|
if (GPR_UNLIKELY(tracer_ != nullptr && tracer_->enabled())) { |
|
|
|
|
if (timeout > Duration::Zero()) { |
|
|
|
|
gpr_log(GPR_INFO, "[polling resolver %p] retrying in %" PRId64 " ms", |
|
|
|
|
this, timeout.millis()); |
|
|
|
|
} else { |
|
|
|
|
gpr_log(GPR_INFO, "[polling resolver %p] retrying immediately", this); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
Ref(DEBUG_LOCATION, "next_resolution_timer").release(); |
|
|
|
|
GRPC_CLOSURE_INIT(&on_next_resolution_, OnNextResolution, this, nullptr); |
|
|
|
|
grpc_timer_init(&next_resolution_timer_, next_try, &on_next_resolution_); |
|
|
|
|
if (GPR_UNLIKELY(tracer_ != nullptr && tracer_->enabled())) { |
|
|
|
|
gpr_log(GPR_INFO, |
|
|
|
|
"[polling resolver %p] returning result: " |
|
|
|
|
"addresses=%s, service_config=%s", |
|
|
|
|
this, |
|
|
|
|
result.addresses.ok() |
|
|
|
|
? absl::StrCat("<", result.addresses->size(), " addresses>") |
|
|
|
|
.c_str() |
|
|
|
|
: result.addresses.status().ToString().c_str(), |
|
|
|
|
result.service_config.ok() |
|
|
|
|
? (*result.service_config == nullptr |
|
|
|
|
? "<null>" |
|
|
|
|
: std::string((*result.service_config)->json_string()) |
|
|
|
|
.c_str()) |
|
|
|
|
: result.service_config.status().ToString().c_str()); |
|
|
|
|
} |
|
|
|
|
GPR_ASSERT(result.result_health_callback == nullptr); |
|
|
|
|
RefCountedPtr<PollingResolver> self = |
|
|
|
|
Ref(DEBUG_LOCATION, "result_health_callback"); |
|
|
|
|
result.result_health_callback = [self = |
|
|
|
|
std::move(self)](absl::Status status) { |
|
|
|
|
self->GetResultStatus(std::move(status)); |
|
|
|
|
}; |
|
|
|
|
result_status_state_ = ResultStatusState::kResultHealthCallbackPending; |
|
|
|
|
result_handler_->ReportResult(std::move(result)); |
|
|
|
|
} |
|
|
|
|
Unref(DEBUG_LOCATION, "OnRequestComplete"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void PollingResolver::GetResultStatus(absl::Status status) { |
|
|
|
|
if (GPR_UNLIKELY(tracer_ != nullptr && tracer_->enabled())) { |
|
|
|
|
gpr_log(GPR_INFO, "[polling resolver %p] result status from channel: %s", |
|
|
|
|
this, status.ToString().c_str()); |
|
|
|
|
} |
|
|
|
|
if (status.ok()) { |
|
|
|
|
// Reset backoff state so that we start from the beginning when the
|
|
|
|
|
// next request gets triggered.
|
|
|
|
|
backoff_.Reset(); |
|
|
|
|
// If a re-resolution attempt was requested while the result-status
|
|
|
|
|
// callback was pending, trigger a new request now.
|
|
|
|
|
if (std::exchange(result_status_state_, ResultStatusState::kNone) == |
|
|
|
|
ResultStatusState::kReresolutionRequestedWhileCallbackWasPending) { |
|
|
|
|
MaybeStartResolvingLocked(); |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
// Set up for retry.
|
|
|
|
|
// InvalidateNow to avoid getting stuck re-initializing this timer
|
|
|
|
|
// in a loop while draining the currently-held WorkSerializer.
|
|
|
|
|
// Also see https://github.com/grpc/grpc/issues/26079.
|
|
|
|
|
ExecCtx::Get()->InvalidateNow(); |
|
|
|
|
Timestamp next_try = backoff_.NextAttemptTime(); |
|
|
|
|
Duration timeout = next_try - ExecCtx::Get()->Now(); |
|
|
|
|
GPR_ASSERT(!have_next_resolution_timer_); |
|
|
|
|
have_next_resolution_timer_ = true; |
|
|
|
|
if (GPR_UNLIKELY(tracer_ != nullptr && tracer_->enabled())) { |
|
|
|
|
if (timeout > Duration::Zero()) { |
|
|
|
|
gpr_log(GPR_INFO, "[polling resolver %p] retrying in %" PRId64 " ms", |
|
|
|
|
this, timeout.millis()); |
|
|
|
|
} else { |
|
|
|
|
gpr_log(GPR_INFO, "[polling resolver %p] retrying immediately", this); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
Ref(DEBUG_LOCATION, "next_resolution_timer").release(); |
|
|
|
|
GRPC_CLOSURE_INIT(&on_next_resolution_, OnNextResolution, this, nullptr); |
|
|
|
|
grpc_timer_init(&next_resolution_timer_, next_try, &on_next_resolution_); |
|
|
|
|
// Reset result_status_state_. Note that even if re-resolution was
|
|
|
|
|
// requested while the result-health callback was pending, we can
|
|
|
|
|
// ignore it here, because we are in backoff to re-resolve anyway.
|
|
|
|
|
result_status_state_ = ResultStatusState::kNone; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void PollingResolver::MaybeStartResolvingLocked() { |
|
|
|
|
// If there is an existing timer, the time it fires is the earliest time we
|
|
|
|
|
// can start the next resolution.
|
|
|
|
|