blob: 99b308a5029565a23830dcd4539fea6425af519c [file] [log] [blame]
# SPDX-FileCopyrightText: 2020 The Magma Authors.
# SPDX-FileCopyrightText: 2022 Open Networking Foundation <support@opennetworking.org>
#
# SPDX-License-Identifier: BSD-3-Clause
import logging
import sys
import grpc
import psutil
from common.service_registry import ServiceRegistry
class GRPCClientManager:
def __init__(
self, service_name: str, service_stub,
max_client_reuse: int = 60,
):
self._client = None
self._service_stub = service_stub
self._service_name = service_name
self._num_client_use = 0
self._max_client_reuse = max_client_reuse
def get_client(self):
"""
get_client returns a grpc client of the specified service in the cloud.
it will return a recycled client until the client fails or the number
of recycling reaches the max_client_use.
"""
if self._client is None or \
self._num_client_use > self._max_client_reuse:
chan = ServiceRegistry.get_rpc_channel(
self._service_name,
ServiceRegistry.CLOUD,
)
self._client = self._service_stub(chan)
self._num_client_use = 0
self._num_client_use += 1
return self._client
def on_grpc_fail(self, err_code):
"""
Try to reuse the grpc client if possible. We are yet to fix a
grpc behavior, where if DNS request blackholes then the DNS request
is retried infinitely even after the channel is deleted. To prevent
running out of fds, we try to reuse the channel during such failures
as much as possible.
"""
if err_code != grpc.StatusCode.DEADLINE_EXCEEDED:
# Not related to the DNS issue
self._reset_client()
if self._num_client_use >= self._max_client_reuse:
logging.info('Max client reuse reached. Cleaning up client')
self._reset_client()
# Sanity check if we are not leaking fds
proc = psutil.Process()
max_fds, _ = proc.rlimit(psutil.RLIMIT_NOFILE)
open_fds = proc.num_fds()
logging.info('Num open fds: %d', open_fds)
if open_fds >= (max_fds * 0.8):
logging.error("Reached 80% of allowed fds. Restarting process")
sys.exit(1)
def _reset_client(self):
self._client = None
self._num_client_use = 0