|  | @@ -47,12 +47,14 @@ HealthCheckClient::HealthCheckClient(
 | 
	
		
			
				|  |  |      const char* service_name,
 | 
	
		
			
				|  |  |      RefCountedPtr<ConnectedSubchannel> connected_subchannel,
 | 
	
		
			
				|  |  |      grpc_pollset_set* interested_parties,
 | 
	
		
			
				|  |  | -    RefCountedPtr<channelz::SubchannelNode> channelz_node)
 | 
	
		
			
				|  |  | +    RefCountedPtr<channelz::SubchannelNode> channelz_node,
 | 
	
		
			
				|  |  | +    RefCountedPtr<ConnectivityStateWatcherInterface> watcher)
 | 
	
		
			
				|  |  |      : InternallyRefCounted<HealthCheckClient>(&grpc_health_check_client_trace),
 | 
	
		
			
				|  |  |        service_name_(service_name),
 | 
	
		
			
				|  |  |        connected_subchannel_(std::move(connected_subchannel)),
 | 
	
		
			
				|  |  |        interested_parties_(interested_parties),
 | 
	
		
			
				|  |  |        channelz_node_(std::move(channelz_node)),
 | 
	
		
			
				|  |  | +      watcher_(std::move(watcher)),
 | 
	
		
			
				|  |  |        retry_backoff_(
 | 
	
		
			
				|  |  |            BackOff::Options()
 | 
	
		
			
				|  |  |                .set_initial_backoff(
 | 
	
	
		
			
				|  | @@ -73,43 +75,21 @@ HealthCheckClient::~HealthCheckClient() {
 | 
	
		
			
				|  |  |    if (GRPC_TRACE_FLAG_ENABLED(grpc_health_check_client_trace)) {
 | 
	
		
			
				|  |  |      gpr_log(GPR_INFO, "destroying HealthCheckClient %p", this);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | -  GRPC_ERROR_UNREF(error_);
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -void HealthCheckClient::NotifyOnHealthChange(grpc_connectivity_state* state,
 | 
	
		
			
				|  |  | -                                             grpc_closure* closure) {
 | 
	
		
			
				|  |  | -  MutexLock lock(&mu_);
 | 
	
		
			
				|  |  | -  GPR_ASSERT(notify_state_ == nullptr);
 | 
	
		
			
				|  |  | -  if (*state != state_) {
 | 
	
		
			
				|  |  | -    *state = state_;
 | 
	
		
			
				|  |  | -    GRPC_CLOSURE_SCHED(closure, GRPC_ERROR_REF(error_));
 | 
	
		
			
				|  |  | -    return;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  notify_state_ = state;
 | 
	
		
			
				|  |  | -  on_health_changed_ = closure;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  void HealthCheckClient::SetHealthStatus(grpc_connectivity_state state,
 | 
	
		
			
				|  |  | -                                        grpc_error* error) {
 | 
	
		
			
				|  |  | +                                        const char* reason) {
 | 
	
		
			
				|  |  |    MutexLock lock(&mu_);
 | 
	
		
			
				|  |  | -  SetHealthStatusLocked(state, error);
 | 
	
		
			
				|  |  | +  SetHealthStatusLocked(state, reason);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  void HealthCheckClient::SetHealthStatusLocked(grpc_connectivity_state state,
 | 
	
		
			
				|  |  | -                                              grpc_error* error) {
 | 
	
		
			
				|  |  | +                                              const char* reason) {
 | 
	
		
			
				|  |  |    if (GRPC_TRACE_FLAG_ENABLED(grpc_health_check_client_trace)) {
 | 
	
		
			
				|  |  | -    gpr_log(GPR_INFO, "HealthCheckClient %p: setting state=%d error=%s", this,
 | 
	
		
			
				|  |  | -            state, grpc_error_string(error));
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  if (notify_state_ != nullptr && *notify_state_ != state) {
 | 
	
		
			
				|  |  | -    *notify_state_ = state;
 | 
	
		
			
				|  |  | -    notify_state_ = nullptr;
 | 
	
		
			
				|  |  | -    GRPC_CLOSURE_SCHED(on_health_changed_, GRPC_ERROR_REF(error));
 | 
	
		
			
				|  |  | -    on_health_changed_ = nullptr;
 | 
	
		
			
				|  |  | +    gpr_log(GPR_INFO, "HealthCheckClient %p: setting state=%s reason=%s", this,
 | 
	
		
			
				|  |  | +            ConnectivityStateName(state), reason);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | -  state_ = state;
 | 
	
		
			
				|  |  | -  GRPC_ERROR_UNREF(error_);
 | 
	
		
			
				|  |  | -  error_ = error;
 | 
	
		
			
				|  |  | +  if (watcher_ != nullptr) watcher_->Notify(state);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  void HealthCheckClient::Orphan() {
 | 
	
	
		
			
				|  | @@ -118,13 +98,8 @@ void HealthCheckClient::Orphan() {
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    {
 | 
	
		
			
				|  |  |      MutexLock lock(&mu_);
 | 
	
		
			
				|  |  | -    if (on_health_changed_ != nullptr) {
 | 
	
		
			
				|  |  | -      *notify_state_ = GRPC_CHANNEL_SHUTDOWN;
 | 
	
		
			
				|  |  | -      notify_state_ = nullptr;
 | 
	
		
			
				|  |  | -      GRPC_CLOSURE_SCHED(on_health_changed_, GRPC_ERROR_NONE);
 | 
	
		
			
				|  |  | -      on_health_changed_ = nullptr;
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  |      shutting_down_ = true;
 | 
	
		
			
				|  |  | +    watcher_.reset();
 | 
	
		
			
				|  |  |      call_state_.reset();
 | 
	
		
			
				|  |  |      if (retry_timer_callback_pending_) {
 | 
	
		
			
				|  |  |        grpc_timer_cancel(&retry_timer_);
 | 
	
	
		
			
				|  | @@ -141,7 +116,7 @@ void HealthCheckClient::StartCall() {
 | 
	
		
			
				|  |  |  void HealthCheckClient::StartCallLocked() {
 | 
	
		
			
				|  |  |    if (shutting_down_) return;
 | 
	
		
			
				|  |  |    GPR_ASSERT(call_state_ == nullptr);
 | 
	
		
			
				|  |  | -  SetHealthStatusLocked(GRPC_CHANNEL_CONNECTING, GRPC_ERROR_NONE);
 | 
	
		
			
				|  |  | +  SetHealthStatusLocked(GRPC_CHANNEL_CONNECTING, "starting health watch");
 | 
	
		
			
				|  |  |    call_state_ = MakeOrphanable<CallState>(Ref(), interested_parties_);
 | 
	
		
			
				|  |  |    if (GRPC_TRACE_FLAG_ENABLED(grpc_health_check_client_trace)) {
 | 
	
		
			
				|  |  |      gpr_log(GPR_INFO, "HealthCheckClient %p: created CallState %p", this,
 | 
	
	
		
			
				|  | @@ -152,10 +127,8 @@ void HealthCheckClient::StartCallLocked() {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  void HealthCheckClient::StartRetryTimer() {
 | 
	
		
			
				|  |  |    MutexLock lock(&mu_);
 | 
	
		
			
				|  |  | -  SetHealthStatusLocked(
 | 
	
		
			
				|  |  | -      GRPC_CHANNEL_TRANSIENT_FAILURE,
 | 
	
		
			
				|  |  | -      GRPC_ERROR_CREATE_FROM_STATIC_STRING(
 | 
	
		
			
				|  |  | -          "health check call failed; will retry after backoff"));
 | 
	
		
			
				|  |  | +  SetHealthStatusLocked(GRPC_CHANNEL_TRANSIENT_FAILURE,
 | 
	
		
			
				|  |  | +                        "health check call failed; will retry after backoff");
 | 
	
		
			
				|  |  |    grpc_millis next_try = retry_backoff_.NextAttemptTime();
 | 
	
		
			
				|  |  |    if (GRPC_TRACE_FLAG_ENABLED(grpc_health_check_client_trace)) {
 | 
	
		
			
				|  |  |      gpr_log(GPR_INFO, "HealthCheckClient %p: health check call lost...", this);
 | 
	
	
		
			
				|  | @@ -489,10 +462,10 @@ void HealthCheckClient::CallState::DoneReadingRecvMessage(grpc_error* error) {
 | 
	
		
			
				|  |  |    const bool healthy = DecodeResponse(&recv_message_buffer_, &error);
 | 
	
		
			
				|  |  |    const grpc_connectivity_state state =
 | 
	
		
			
				|  |  |        healthy ? GRPC_CHANNEL_READY : GRPC_CHANNEL_TRANSIENT_FAILURE;
 | 
	
		
			
				|  |  | -  if (error == GRPC_ERROR_NONE && !healthy) {
 | 
	
		
			
				|  |  | -    error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("backend unhealthy");
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  health_check_client_->SetHealthStatus(state, error);
 | 
	
		
			
				|  |  | +  const char* reason = error == GRPC_ERROR_NONE && !healthy
 | 
	
		
			
				|  |  | +                           ? "backend unhealthy"
 | 
	
		
			
				|  |  | +                           : grpc_error_string(error);
 | 
	
		
			
				|  |  | +  health_check_client_->SetHealthStatus(state, reason);
 | 
	
		
			
				|  |  |    seen_response_.Store(true, MemoryOrder::RELEASE);
 | 
	
		
			
				|  |  |    grpc_slice_buffer_destroy_internal(&recv_message_buffer_);
 | 
	
		
			
				|  |  |    // Start another recv_message batch.
 | 
	
	
		
			
				|  | @@ -603,7 +576,7 @@ void HealthCheckClient::CallState::RecvTrailingMetadataReady(
 | 
	
		
			
				|  |  |            grpc_slice_from_static_string(kErrorMessage));
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |      self->health_check_client_->SetHealthStatus(GRPC_CHANNEL_READY,
 | 
	
		
			
				|  |  | -                                                GRPC_ERROR_NONE);
 | 
	
		
			
				|  |  | +                                                kErrorMessage);
 | 
	
		
			
				|  |  |      retry = false;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    self->CallEnded(retry);
 |