diff --git a/src/core/ext/filters/client_channel/client_channel.cc b/src/core/ext/filters/client_channel/client_channel.cc index 40318cb557b..3fea29662fd 100644 --- a/src/core/ext/filters/client_channel/client_channel.cc +++ b/src/core/ext/filters/client_channel/client_channel.cc @@ -1548,6 +1548,15 @@ void ClientChannel::UpdateServiceConfigInDataPlaneLocked() { // Process calls that were queued waiting for the resolver result. for (ResolverQueuedCall* call = resolver_queued_calls_; call != nullptr; call = call->next) { + // If there are a lot of queued calls here, resuming them all may cause us + // to stay inside C-core for a long period of time. All of that work would + // be done using the same ExecCtx instance and therefore the same cached + // value of "now". The longer it takes to finish all of this work and exit + // from C-core, the more stale the cached value of "now" may become. This + // can cause problems whereby (e.g.) we calculate a timer deadline based + // on the stale value, which results in the timer firing too early. To + // avoid this, we invalidate the cached value for each call we process. + ExecCtx::Get()->InvalidateNow(); grpc_call_element* elem = call->elem; CallData* calld = static_cast(elem->call_data); grpc_error_handle error = GRPC_ERROR_NONE; @@ -1660,6 +1669,15 @@ void ClientChannel::UpdateStateAndPickerLocked( // Re-process queued picks. for (LbQueuedCall* call = lb_queued_calls_; call != nullptr; call = call->next) { + // If there are a lot of queued calls here, resuming them all may cause us + // to stay inside C-core for a long period of time. All of that work would + // be done using the same ExecCtx instance and therefore the same cached + // value of "now". The longer it takes to finish all of this work and exit + // from C-core, the more stale the cached value of "now" may become. This + // can cause problems whereby (e.g.) we calculate a timer deadline based + // on the stale value, which results in the timer firing too early. To + // avoid this, we invalidate the cached value for each call we process. + ExecCtx::Get()->InvalidateNow(); grpc_error_handle error = GRPC_ERROR_NONE; if (call->lb_call->PickSubchannelLocked(&error)) { call->lb_call->AsyncPickDone(error);