Почему этот вызов API Google Secret Manager приводит к зависанию моего приложения Django?
Вкратце:
У меня есть приложение Django, обслуживаемое Apache на виртуальной машине Google Compute Engine.
Я хочу получить доступ к секрету из Google Secret Manager в моем Python-коде (когда приложение Django инициализируется).
Когда я выполняю команду 'python manage.py runserver', секрет успешно получен. Однако, когда я заставляю Apache запустить мое приложение, оно зависает при отправке запроса менеджеру секретов.
Слишком много деталей:
Я следовал ответу на этот вопрос GCP VM Instance is not unable to access secrets from Secret Manager despite of appropriate Roles. Я создал учетную запись службы (не по умолчанию) и присвоил ей область 'cloud-platform'. Я также назначил ей роль 'Secret Manager Admin' в веб-консоли.
После того, как я столкнулся с проблемой, я загрузил json-ключ для учетной записи службы из веб-консоли и установил env-вар GOOGLE_APPLICATION_CREDENTIALS, чтобы указать на него.
Когда я запускаю сервер django непосредственно на виртуальной машине, все работает нормально. Когда я позволяю Apache запустить приложение, я вижу из журналов, что учетная запись службы успешно загружена.
Однако, когда я делаю первый вызов API, через google.cloud.secretmanager.SecretManagerServiceClient.list_secret_versions, приложение зависает. Я даже не получаю ошибку 500 в браузере, только значок вечной загрузки. Я проследил выполнение до:
grpc._channel._UnaryUnaryMultiCallable._blocking, строка 926 : 'call = self._channel.segregated_call(...'
Он никогда не проходит дальше этой строки. Я не мог понять, куда идет этот вызов, поэтому я не мог проверить его дальше этого.
Мысли
Я не очень хорошо понимаю учетные записи служб GCP / доступ к API. Я не могу понять, почему эта разница возникает между сервером django dev и apache, учитывая, что они оба используют одни и те же учетные данные учетной записи службы из json. Я также удивлен, что приложение просто зависает в библиотеке google, а не выбрасывает исключение. Есть даже опция таймаута при отправке запроса, но ее изменение ничего не меняет.
Интересно, связано ли это как-то с тем, что я запускаю сервер django под своей учетной записью, но apache использует любую учетную запись пользователя, которую он использует?
Проблема, по-видимому, заключается в том, что поведение форков в Apache каким-то образом нарушает работу gRPC. Я не смог установить точную причину, но после того, как я начал подозревать, что проблема в форке, я нашел эту старую проблему gRPC, которая указывает, что форк - это немного сложная область.
Я пытался перенастроить Apache на использование различных 'Multi-processing Module', но поскольку мой опыт в этом ограничен, я не смог заставить gRPC работать ни под одним из них.
В конце концов, я перешел на использование nginx/uwsgi вместо Apache/mod_wsgi, и у меня не возникло такой проблемы. Если вы пытаетесь решить подобную проблему и вам приходится использовать Apache, я бы посоветовал подробнее изучить форки Apache, то, как gRPC обрабатывает форки, и различные MPM, доступные для Apache.