FastAPI не видит новый .env: настройки и кэш Settings

В .env поменяли адрес сервиса, а FastAPI продолжает обращаться по старому. Файл на диске правильный, опечаток нет. Прежде чем снова пересобирать весь проект, стоит выяснить три вещи: откуда процесс получает переменную, когда он читает файл и хранит ли уже готовый объект настроек.

Это разные источники старого значения. Переменная процесса может перекрывать .env. Файл может искаться в другом рабочем каталоге. А закэшированный Settings может вообще больше не читать ни файл, ни окружение.

Настройки создаются в определённый момент

Установите python -m pip install pydantic-settings. Этот пример можно запустить отдельно от FastAPI:

import os
from functools import lru_cache
from pydantic_settings import BaseSettings, SettingsConfigDict

class Settings(BaseSettings):
    model_config = SettingsConfigDict(env_prefix="DEMO_", env_file=".env")
    service_name: str = "catalog"

@lru_cache
def get_settings():
    return Settings()

os.environ["DEMO_SERVICE_NAME"] = "first"
print(get_settings().service_name)
os.environ["DEMO_SERVICE_NAME"] = "second"
print(get_settings().service_name)
get_settings.cache_clear()
print(get_settings().service_name)

Вывод: first, first, second. Во втором вызове возвращается прежний объект. cache_clear здесь нужен для опыта; в рабочем сервисе не стоит превращать его в публичную кнопку произвольного обновления секретов.

Как искать источник значения

Сначала проверьте рабочий каталог процесса и наличие ожидаемого файла. Затем выясните, передаёт ли Docker Compose, systemd или оболочка ту же переменную непосредственно в окружение. В стандартном порядке источников pydantic-settings значение окружения приоритетнее .env; настройка источников в самом проекте может этот порядок изменить.

Для диагностики используйте безопасное поле вроде имени окружения или адреса без учётных данных. Печатать весь Settings, DATABASE_URL с паролем или содержимое .env в журнал не нужно.

Редактирование .env не меняет окружение уже запущенного процесса. Если секрет передаёт система запуска, обновите его там и перезапустите процесс штатным способом. У каждого воркера свой объект настроек, поэтому обновиться должны все нужные экземпляры.

Что проверять в тестах

Тест, меняющий окружение через monkeypatch, может получить кэш от предыдущего теста. Очищайте get_settings.cache_clear() до создания проверяемого объекта и после теста. Иначе тесты зависят от порядка запуска.

Полезно разделить тест приоритетов источников и тест потребителя настроек. Первому нужен настоящий Settings, второму часто достаточно подмены зависимости FastAPI. Смежный случай на уровне контейнеров — почему Compose использует старое значение окружения.

Собрать следующий этап проекта

Если проект уже вырос из одного файла, пригодится следующий шаг: разделить код на пакеты, описать интерфейсы типами и покрыть поведение тестами. Этому посвящён бесплатный курс Python для продвинутых: от объектной модели до небольшого приложения с конфигурацией и логированием.

Посмотреть программу: Python для продвинутых: ООП, типизация и тестирование

Проверить детали: FastAPI: Settings и кэш, Pydantic Settings.

Продолжить на практике

  • Python для продвинутых: ООП, типизация и тестирование ↗

    Практический курс-мост от базового Python к разработке поддерживаемых приложений. Вы разберётесь со структурой пакетов, объектной моделью, современной типизацией и автоматическими тестами, а затем соедините эти инструменты в небольшом приложении с хранением данных и логированием.

  • FastAPI для начинающих: API с базой данных и тестами ↗

    Соберёте свой первый полноценный backend на FastAPI: с базой данных, регистрацией, JWT-авторизацией и автотестами. 34 коротких урока и 140 заданий с проверкой — бесплатно.