Инструкция пользователя Облака УВА Advanced
Правила пользования Облаком УВА Advanced
- Сбор персональных данных с использованием облачных ресурсов УВА запрещен. Перед началом работы, пожалуйста, изучите 152-ФЗ.
- Не отключайте опцию подключения к виртуальной машине с правами root. Нарушение этого правила может привести к блокировке вашей машины.
- Не храните в базах данных и объектном хранилище информацию, не предназначенную для широкой аудитории. Пользование сервером PostgreSQL и бакетами в Облаке УВА организовано по принципу💡
все видят всех и могут выгружать всё, но редактировать и удалять сущность может только ее создатель
- Давайте сущностям осмысленные имена. В названиях однотипных придерживайтесь шаблона/структуры. При создании базы данных заполняйте поле Комментарий. Пожалуйста, думайте об удобстве использования материалов вашими коллегами.
- Вопросы по работе сервиса, предложения и обнаруженные ошибки, пожалуйста, направляйте по адресам:
- Меределин Евгений, eimeredelin@sberbank.ru
- копия письма: Радик Махмутов, rgmakhmutov@sberbank.ru
Что вы получаете на руки
Виртуальная машина
- Конфигурация: 4 vCPUs, 8 GB RAM, Intel Ice Lake 2.6GHz, диск High I/O 60 GB, Ubuntu 24.04. Интернет 50 Mbps.
- Внешний IP для подключения к виртуальной машине по SSH. В примере Подключение к виртуальной машине:
188.72.107.76
.
- IP вашей виртуальной машины в Облаке УВА. Понадобится, если делать API.
- Имя пользователя, состоящего в группе sudo, и его пароль. Пользователь в примере
user-demo
.
Доступ к серверу PostgreSQL
- Имя сервера PostgreSQL и его IP-адрес. В примере Подключение к серверу PostgreSQL:
postgres-demo
,10.0.14.19
.
- Имя вашей учетной записи на сервере и пароль от нее. Пользователь в примере
user-demo
.
Доступ к объектному хранилищу
- Access key, secret key, endpoint и region для управления с помощью клиентов объектных хранилищ или boto3.
- Имя созданного для вас бакета. В примере Подключение к объектному хранилищу:
user-demo-bucket
.
Подключение к виртуальной машине
- Сгенерируйте пароль (passphrase) для SSH-ключа и сохраните его в надежном месте. Пожалуйста, не пренебрегайте созданием passphrase — он понадобится для подключения к серверу PostgreSQL. Например, создайте буквенно-цифровую последовательность длиной 50 символов этим генератором.
- Сгенерируйте SSH-ключ на локальной машине:
$ ssh-keygen Generating public/private ed25519 key pair. Enter file in which to save the key (/c/Users/user/.ssh/id_ed25519): Enter passphrase for "/c/Users/user/.ssh/id_ed25519" (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /c/Users/user/.ssh/id_ed25519 Your public key has been saved in /c/Users/user/.ssh/id_ed25519.pub The key fingerprint is: SHA256:apfCa4esUZko7sJjHEwkE2eMpvrRUQlucdrf6RXZ9Y0 user@AsusVivobook The key's randomart image is: +--[ED25519 256]--+ |.+o o... .| |+=.. =o o oo| |=. +.. o E o| |.. ... + . . . | |+ ....+ S o . | |.+...o . o . | |o.o...=.o . | |.*. o++. | |..o .o.. | +----[SHA256]-----+
- Скопируйте публичную часть ключа,
id_ed25519.pub
, с локальной машины на виртуальную. Измените путь до ключа на локальной машине на свой.$ scp C:/Users/user/.ssh/id_ed25519.pub user-demo@188.72.107.76:/home/user-demo/.ssh/authorized_keys user-demo@188.72.107.76's password: id_ed25519.pub 100% 99 7.3KB/s 00:00
- Подключитесь к виртуальной машине по SSH:
$ ssh user-demo@188.72.107.76 Enter passphrase for key '/c/Users/user/.ssh/id_ed25519': Welcome to Ubuntu 24.04.2 LTS (GNU/Linux 6.8.0-71-generic x86_64) * Documentation: https://help.ubuntu.com * Management: https://landscape.canonical.com * Support: https://ubuntu.com/pro System information as of Wed Jul 30 02:20:05 PM MSK 2025 System load: 0.0 Processes: 113 Usage of /: 8.6% of 39.26GB Users logged in: 0 Memory usage: 10% IPv4 address for eth0: 10.0.14.15 Swap usage: 0% Expanded Security Maintenance for Applications is not enabled. 0 updates can be applied immediately. Enable ESM Apps to receive additional future security updates. See https://ubuntu.com/esm or run: sudo pro status Welcome to Elastic Cloud Service
Подключение к серверу PostgreSQL

- Установите PostgreSQL на локальную машину, включая предлагаемый во время установки pgAdmin.
- Создайте базу данных и схему (schema) внутри нее. Внутри схемы вы сможете создавать таблицы и другие сущности. Скриншот ниже показывает пример ошибки, которую получит другой пользователь при попытке изменить вашу таблицу.
- Быть владельцем сущности не всегда означает право изменять ее: владелец может делегировать право, хотя сам при этом может им активно и не обладать. Чтобы писать в таблицы, например, с помощью SQLAlchemy, выполните небольшая донастройку по примеру на скришотах ниже. Откройте свойства принадлежащих вам, т.е. созданных вами, сущностей (БД, схема, таблица и т.д.) и дайте самому себе или коллегам необходимые права. Во вкладке Security задаются права на уже созданные сущности, в Default Privileges — на те, которые будут созданы внутри редактируемой сущности.
- Если вы используете SQLAlchemy ORM, не забудьте указать имя схемы. Таблица в примере, reviews, живет на схеме bankiru-schema. Если не указать это явно, SQLAlchemy будет искать/писать таблицу на дефолтной для постгреса схеме public, к которой сейчас у пользователей доступа нет, и это приведет к
InsufficientPermissionException
. Для установки схемы воспользуйтесь одним из двух способов:- определите схему в метаданных базового класса
Base
, если схему нужно распространить на все дочерние модели;
- переопределите схему в дандер-атрибуте
__table_args__
конкретной модели, если схема задается для той или иной таблицы индивидуально.
# https://github.com/EvgenyMeredelin/bankiru-dbapi/blob/main/models.py from sqlalchemy import MetaData from sqlalchemy.orm import declarative_base Base = declarative_base(metadata=MetaData(schema="bankiru-schema")) class Review(Base): __tablename__ = "reviews" __table_args__ = {"schema": "bankiru-schema"} ...
- определите схему в метаданных базового класса
Подключение к объектному хранилищу
- Установите OBS Browser Plus на локальную машину.
Что дальше
- создайте SSH-ключ на виртуальной машине и скопируйте его публичную часть в свою учетную запись на GitHub;
- узнайте, как устанавливать python-пакеты и управлять проектами с помощью замечательного менеджера uv;
- узнайте, как подключиться к вашим базам данных на сервере PostgreSQL с помощью SQLAlchemy;
- узнайте, как управлять запуском вашего приложения с помощью systemd;
- узнайте, как управлять контейнерами и подами с помощью Podman;
VM + PG + S3 = 🚀
Пример простого сервиса, который использует все услуги Облака УВА Advanced, доступные на момент написания в августе 2025: виртуальная машина, сервер PostgreSQL и объектное хранилище. Пожалуйста, проходите после выполнения инструкций выше.
Сервис сбора и хранения негативных отзывов с banki.ru состоит из двух частей:
- Парсер. В начале наступившего дня собирает данные за истекшие сутки и отправляет их в API базы данных.
- API базы данных. Публикует пришедшие от парсера новые записи в базе данных. После каждого коммита (добавления или удаления записей) делает резервную копию базы данных в формате parquet и перезаписывает предыдущую версию в бакете объектного хранилища. Принимает запрос на получение из БД выборки, ограниченной датами, в заданном формате. Выборка предоставляется в ответе в виде прямой ссылки на скачивание файла из бакета объектного хранилища.
Рассмотрим разработку и запуск API как отдельного проекта. Ход работы с парсером аналогичен.
План действий. Разработка API ведется на [локальной] машине с Windows. Площадка запуска и постоянной работы — виртуальная машина с Ubuntu. Мы создадим и подготовим проект на локальной машине, создадим для него репозиторий на GitHub, склонируем репозиторий на виртуальную машину, запустим API и посмотрим на его работу.
Инструменты: uv, GitHub CLI (gh
), systemd, HTTPie CLI, Pydantic Logfire.
В примере используется SSH-клиент Termius с двумя профилями: PowerShell и bash из поставки Git для Windows (C:\Program Files\Git\bin\bash.exe). Если не указано особо, команда выполняется в bash.
- Установка uv в Windows. В PowerShell:
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex" Downloading uv 0.8.9 (x86_64-pc-windows-msvc) Installing to C:\Users\user\.local\bin uv.exe uvx.exe uvw.exe everything's installed!
uv --version uv 0.8.9 (68c0bf8a2 2025-08-11)
- Создание проекта с помощью uv:
/d/git $ uv init bankiru-dbapi Initialized project `bankiru-dbapi` at `D:\git\bankiru-dbapi`
- Создание виртуального окружения, установка зависимостей. Изучите документацию uv, если вашему проекту требуется какая-то конкретная версия интерпретатора и чтобы дать виртуальному окружению имя, отличное от
.venv
по умолчанию./d/git $ cd bankiru-dbapi/
/d/git/bankiru-dbapi (main) $ uv add aiobotocore alembic environs fastapi[standard] logfire[fastapi] pandas psycopg[binary,pool] py-spoo-url pyarrow sqlalchemy Using CPython 3.13.2 Creating virtual environment at: .venv Resolved 104 packages in 814ms Installed 102 packages in 3.93s + aiobotocore==2.24.0 + aiohappyeyeballs==2.6.1 + aiohttp==3.12.15 ... + wrapt==1.17.3 + yarl==1.20.1 + zipp==3.23.0
pyproject.toml
:/d/git/bankiru-dbapi (main) $ cat pyproject.toml [project] name = "bankiru-dbapi" version = "0.1.0" description = "Add your description here" readme = "README.md" requires-python = ">=3.13" dependencies = [ "aiobotocore>=2.24.0", "alembic>=1.16.4", "environs>=14.3.0", "fastapi[standard]>=0.116.1", "logfire[fastapi]>=4.3.3", "pandas>=2.3.1", "psycopg[binary,pool]>=3.2.9", "py-spoo-url>=0.0.6", "pyarrow>=21.0.0", "sqlalchemy>=2.0.43", ]
Заполним поле
description
. В проекте естьalembic
, но создание системы миграций здесь не рассматривается. Для чтения переменных окружения используетсяenvirons
. Обратите также внимание на замечательную библиотеку dataclass-wizard.
- Мы поработали и написали в корневой папке проекта несколько py-модулей и/или пакетов. Также мы добавим:
- файл с переменными окружения
.env
;
- файл
.env.example
, чтобы использующие код знали, какие переменные окружения он ожидает;
- файл
.gitignore
, исключающий из отслеживания.env
и.venv
;
- юнит systemd
bankiru-dbapi.service
для запуска API на виртуальной машине.
/d/git/bankiru-dbapi (main) $ ls -a -1 . .. .env .env.example .git .gitignore .python-version .venv README.md alembic alembic.ini bankiru-dbapi.service botocore_client.py database.py handlers.py logfire_auto_tracing.py main.py models.py pyproject.toml schemas.py uv.lock
- файл с переменными окружения
.env.example
:/d/git/bankiru-dbapi (main) $ cat .env.example API_TOKEN=database_api_access_token LOGFIRE_TOKEN=logfire_project_write_token # all placeholders refer to the postgres server POSTGRES_URL=postgresql+psycopg://username:password@ip/db_name AWS_REQUEST_CHECKSUM_CALCULATION=when_required AWS_RESPONSE_CHECKSUM_VALIDATION=when_required OBS_BUCKET=obs_bucket_name OBS_ACCESS_KEY=obs_access_key OBS_SECRET_KEY=obs_secret_key OBS_REGION=ru-moscow OBS_ENDPOINT=https://obs.ru-moscow-1.hc.sbercloud.ru ECS_PRIVATE_IP=ecs_internal_ip ECS_PUBLIC_IP=ecs_external_ip # the port your FastAPI app listens to must be allowed by your security group, # contact eimeredelin@sberbank.ru to open port on demand ECS_PORT=ecs_port REVIEWS_ENDPOINT=http://ecs_external_ip:ecs_port/reviews
Токен доступа к API и токен Logfire специфичны для этого проекта. Остальные используемые здесь данные ваш отдел получит в момент предоставления облачных ресурсов. Два исключения:
db_name
в строке подключения к БД: базу(-ы) данных отдел создает самостоятельно;
ecs_port
: если вы делаете публичный API, который должен быть доступен из интернета, вы самостоятельно выбираете номер порта и делаете заявку на его открытие у вашей виртуальной машины.
bankiru-dbapi.service
:/d/git/bankiru-dbapi (main) $ cat bankiru-dbapi.service [Unit] Description=bankiru-dbapi After=syslog.target After=network.target [Service] Type=simple User=evm WorkingDirectory=/home/evm/bankiru-dbapi ExecStart=/home/evm/bankiru-dbapi/.venv/bin/python /home/evm/bankiru-dbapi/logfire_auto_tracing.py Restart=always [Install] WantedBy=multi-user.target
- Выпуск токена доступа/аутентификации personal access token (PAT) на GitHub здесь. Требование к токену: The minimum required scopes are
repo
,read:org
,admin:public_key
.
- Установка GitHub CLI в Windows: скачать msi или с помощью winget.
/d/git/bankiru-dbapi (main) $ winget install --id GitHub.cli Found GitHub CLI [GitHub.cli] Version 2.76.2 This application is licensed to you by its owner. Microsoft is not responsible for, nor does it grant any licenses to, third-party packages. Downloading https://github.com/cli/cli/releases/download/v2.76.2/gh_2.76.2_windows_amd64.msi ██████████████████████████████ 17.4 MB / 17.4 MB Successfully verified installer hash Starting package install... The installer will request to run as administrator. Expect a prompt. Successfully installed
/d/git/bankiru-dbapi (main) $ gh --version gh version 2.76.2 (2025-07-30) https://github.com/cli/cli/releases/tag/v2.76.2
- Аутентификация в GitHub CLI с использованием токена из п.7. Публичная часть SSH-ключа будет скопирована и появится здесь с назначенным ему именем.
/d/git/bankiru-dbapi (main) $ gh auth login ? Where do you use GitHub? GitHub.com ? What is your preferred protocol for Git operations on this host? SSH ? Upload your SSH public key to your GitHub account? C:\Users\user\.ssh\id_ed25519.pub ? Title for your SSH key: (GitHub CLI) ... ? Title for your SSH key: ... ? How would you like to authenticate GitHub CLI? Paste an authentication token Tip: you can generate a Personal Access Token here https://github.com/settings/tokens The minimum required scopes are 'repo', 'read:org', 'admin:public_key'. ? Paste your authentication token: **************************************** - gh config set -h github.com git_protocol ssh ✓ Configured git protocol ✓ Uploaded the SSH key to your GitHub account: C:\Users\user\.ssh\id_ed25519.pub ✓ Logged in as EvgenyMeredelin
Токен аутентификации хранится безопасно:
/d/git/bankiru-dbapi (main) $ gh auth status github.com ✓ Logged in to github.com account EvgenyMeredelin (keyring) - Active account: true - Git operations protocol: ssh - Token: ghp_************************************ - Token scopes: ...
- Коммит проекта. Но перед этим добавим описание в
README.md
./d/git/bankiru-dbapi (main) $ git add .
/d/git/bankiru-dbapi (main) $ git commit -m "First commit" [main (root-commit) 3dbd33a] First commit 19 files changed, 2808 insertions(+) create mode 100644 .env.example create mode 100644 .gitignore create mode 100644 .python-version create mode 100644 README.md create mode 100644 alembic.ini create mode 100644 alembic/README create mode 100644 alembic/env.py create mode 100644 alembic/script.py.mako create mode 100644 alembic/versions/45600a192211_initial_migration.py create mode 100644 bankiru-dbapi.service create mode 100644 botocore_client.py create mode 100644 database.py create mode 100644 handlers.py create mode 100644 logfire_auto_tracing.py create mode 100644 main.py create mode 100644 models.py create mode 100644 pyproject.toml create mode 100644 schemas.py create mode 100644 uv.lock
- Создание репозитория и пуш коммита в него. Источник — текущая папка, поэтому репозиторий получит ее имя:
bankiru-dbapi
./d/git/bankiru-dbapi (main) $ gh repo create --source=. --private --push ✓ Created repository EvgenyMeredelin/bankiru-dbapi on github.com https://github.com/EvgenyMeredelin/bankiru-dbapi ✓ Added remote git@github.com:EvgenyMeredelin/bankiru-dbapi.git Enter passphrase for key '/c/Users/user/.ssh/id_ed25519': Enumerating objects: 23, done. Counting objects: 100% (23/23), done. Delta compression using up to 8 threads Compressing objects: 100% (21/21), done. Writing objects: 100% (23/23), 99.42 KiB | 1.33 MiB/s, done. Total 23 (delta 1), reused 0 (delta 0), pack-reused 0 (from 0) remote: Resolving deltas: 100% (1/1), done. To github.com:EvgenyMeredelin/bankiru-dbapi.git * [new branch] HEAD -> main branch 'main' set up to track 'origin/main'. ✓ Pushed commits to git@github.com:EvgenyMeredelin/bankiru-dbapi.git
- Чтение переменных окружения и подключение к виртуальной машине:
/d/git/bankiru-dbapi (main) $ . .env
/d/git/bankiru-dbapi (main) $ ssh evm@$ECS_PUBLIC_IP Enter passphrase for key '/c/Users/user/.ssh/id_ed25519': Welcome to Ubuntu 24.04.3 LTS (GNU/Linux 6.8.0-71-generic x86_64) * Documentation: https://help.ubuntu.com * Management: https://landscape.canonical.com * Support: https://ubuntu.com/pro ...
- Установка uv в Ubuntu:
evm@ecs-evm:~$ curl -LsSf https://astral.sh/uv/install.sh | sh downloading uv 0.8.9 x86_64-unknown-linux-gnu no checksums to verify installing to /home/evm/.local/bin uv uvx everything's installed!
evm@ecs-evm:~$ uv --version uv 0.8.9
- По причине несовершенства механизма хранения гитом секретов в Linux мы не будем устанавливать GitHub CLI в Ubuntu. Создадим SSH-ключ по пп.1-2 раздела Подключение к виртуальной машине — с той лишь разницей, что это нужно сделать не на локальной машине, а на виртуальной. Скопируем руками публичную часть ключа и создадим новый ключ в разделе SSH keys здесь.
evm@ecs-evm:~$ cat .ssh/id_ed25519.pub ssh-ed25519 ...
- Клонирование репозитория на виртуальную машину. Ссылку, соответствующую протоколу, в т.ч. SSH, можно скопировать со страницы репозитория (зеленая кнопка Code).
evm@ecs-evm:~$ git clone git@github.com:EvgenyMeredelin/bankiru-dbapi.git Cloning into 'bankiru-dbapi'... remote: Enumerating objects: 23, done. remote: Counting objects: 100% (23/23), done. remote: Compressing objects: 100% (20/20), done. remote: Total 23 (delta 1), reused 23 (delta 1), pack-reused 0 (from 0) Receiving objects: 100% (23/23), 99.42 KiB | 530.00 KiB/s, done. Resolving deltas: 100% (1/1), done.
- (Вос)создание виртуального окружения:
evm@ecs-evm:~$ cd bankiru-dbapi/ evm@ecs-evm:~/bankiru-dbapi$ uv sync Using CPython 3.13.5 Creating virtual environment at: .venv Resolved 104 packages in 26ms Prepared 46 packages in 2.63s Installed 102 packages in 620ms + aiobotocore==2.24.0 + aiohappyeyeballs==2.6.1 + aiohttp==3.12.15 ... + wrapt==1.17.3 + yarl==1.20.1 + zipp==3.23.0
- Откроем второй терминал и скопируем файл с переменными окружения
.env
с локальной машины на виртуальную:/d/git/bankiru-dbapi (main) $ . .env
/d/git/bankiru-dbapi (main) $ scp .env evm@$ECS_PUBLIC_IP:/home/evm/bankiru-dbapi/ Enter passphrase for key '/c/Users/user/.ssh/id_ed25519': .env 100% 704 50.7KB/s 00:00
Теперь весь проект на месте:
evm@ecs-evm:~/bankiru-dbapi$ ls -a -1 . .. alembic alembic.ini bankiru-dbapi.service botocore_client.py database.py .env .env.example .git .gitignore handlers.py logfire_auto_tracing.py main.py models.py pyproject.toml .python-version README.md schemas.py uv.lock .venv
- Скопируем подготовленный в п.6 юнит systemd и запустим его:
evm@ecs-evm:~/bankiru-dbapi$ sudo cp bankiru-dbapi.service /etc/systemd/system evm@ecs-evm:~/bankiru-dbapi$ sudo systemctl daemon-reload evm@ecs-evm:~/bankiru-dbapi$ sudo systemctl enable bankiru-dbapi.service Created symlink /etc/systemd/system/multi-user.target.wants/bankiru-dbapi.service → /etc/systemd/system/bankiru-dbapi.service. evm@ecs-evm:~/bankiru-dbapi$ sudo systemctl start bankiru-dbapi.service
Юнит работает:
evm@ecs-evm:~$ sudo systemctl status bankiru-dbapi.service ● bankiru-dbapi.service - bankiru-dbapi Loaded: loaded (/etc/systemd/system/bankiru-dbapi.service; enabled; preset: enabled) Active: active (running) since Wed 2025-08-13 21:17:43 MSK; 4s ago Main PID: 34936 (python) Tasks: 11 (limit: 4144) Memory: 124.8M (peak: 125.2M) CPU: 1.849s CGroup: /system.slice/bankiru-dbapi.service └─34936 /home/evm/bankiru-dbapi/.venv/bin/python /home/evm/bankiru-dbapi/logfire_auto_tracing.py Aug 13 21:17:43 ecs-evm systemd[1]: Started bankiru-dbapi.service - bankiru-dbapi. Aug 13 21:17:43 ecs-evm python[34936]: Logfire project URL: https://logfire-us.pydantic.dev/... Aug 13 21:17:44 ecs-evm python[34936]: INFO: Started server process [34936] Aug 13 21:17:44 ecs-evm python[34936]: INFO: Waiting for application startup. Aug 13 21:17:44 ecs-evm python[34936]: INFO: Application startup complete. Aug 13 21:17:44 ecs-evm python[34936]: INFO: Uvicorn running on http://... (Press CTRL+C to quit)
- Итак, API готов к работе. Парсер поднимается аналогично. Мы создали на сервере базу данных, и парсер уже насобирал в нее данные. Установим на локальной машине Chocolatey и HTTPie CLI. В PowerShell:
Run
Get-ExecutionPolicy
. If it returnsRestricted
, then runSet-ExecutionPolicy AllSigned
orSet-ExecutionPolicy Bypass -Scope Process
.Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
choco --version 2.5.0
choco install httpie Chocolatey v2.5.0 Installing the following packages: httpie By installing, you accept licenses for the packages. Downloading package from source 'https://community.chocolatey.org/api/v2/' Progress: Downloading httpie 3.2.2... 100% ... Successfully installed httpie-3.2.2 The install of httpie was successful. Software install location not explicitly set, it could be in package or default install location of installer. Chocolatey installed 1/1 packages. See the log for details (C:\ProgramData\chocolatey\logs\chocolatey.log).
- Вернемся в bash и рассмотрим несколько примеров работы API.
Чтение записей. Отзывы за первую неделю августа 2025 в xlsx. Ссылка валидна ограниченное время. Ответ200 OK
./d/git/bankiru-dbapi (main) $ http GET $REVIEWS_ENDPOINT API-Token:$API_TOKEN \ > startDate==20250801 endDate==20250807 outputFormat==xlsx \ > --format-options json.sort_keys:false HTTP/1.1 200 OK content-length: 136 content-type: application/json date: Thu, 14 Aug 2025 07:58:48 GMT server: uvicorn { "startDate": "2025-08-01", "endDate": "2025-08-07", "outputFormat": "xlsx", "generateUrl": true, "url": "https://spoo.me/dv7ta3", "comment": null }
То же в HTTPie desktop:
HTTPie desktop app С параметрами по умолчанию получим всю БД в parquet:
/d/git/bankiru-dbapi (main) $ http GET $REVIEWS_ENDPOINT API-Token:$API_TOKEN --unsorted HTTP/1.1 200 OK date: Thu, 14 Aug 2025 08:00:09 GMT server: uvicorn content-length: 123 content-type: application/json { "startDate": null, "endDate": null, "outputFormat": "parquet", "generateUrl": true, "url": "https://spoo.me/OuJjmw", "comment": null }
- Добавление записей. Сымитируем работу парсера и добавим в БД одну запись (представим, что парсер отправил список, в котором единственная запись):
/d/git/bankiru-dbapi (main) $ cat reviews.json [ { "datePublished": "2026-01-01 01:23:45", "reviewBody": "Я закопал монетки, и они пропали...", "bankName": "Банк Поле Чудес", "url": "https://banki.ru/buratino-review", "location": "Сказочный город", "product": "Вклад" } ]
/d/git/bankiru-dbapi (main) $ http POST $REVIEWS_ENDPOINT API-Token:$API_TOKEN < reviews.json HTTP/1.1 201 Created content-length: 4 content-type: application/json date: Thu, 14 Aug 2025 08:01:50 GMT server: uvicorn null
Ответ
null
со статусом201 Created
, потому что парсеру ответ не требуется. Как сказано в описании API выше, после каждого коммита (добавления или удаления записей) API создает бэкап базы данных в parquet и перезаписывает предыдущую версию в бакете объектного хранилища:Логика проста. Если это выборка по запросу пользователя, то API дает информативный ответ с полями, описывающими выборку, а файлу дается уникальное uuid-имя. Если эта выборка — автоматический бэкап, спровоцированный парсером, то осмысленный ответ не требуется, а файл в parquet получает [статичное] предопределенное имя
bankiru_reviews_db_backup
, и это приводит к перезаписи предыдущего бэкапа.Так наша запись выглядит в БД. На скриншоте 5 последних записей, начиная с последней.
- Удаление записей. Удалим нашу запись, отправив соответствующему эндпоинту массив из одного id, — id записи к удалению:
/d/git/bankiru-dbapi (main) $ echo '[220345]' | http DELETE $REVIEWS_ENDPOINT API-Token:$API_TOKEN HTTP/1.1 204 No Content content-type: application/json date: Thu, 14 Aug 2025 08:06:48 GMT server: uvicorn
Ожидаемый ответ
204 No Content
, запись удалена, а бэкап обновлен, что видно по свежей дате последнего изменения в бакете:
- Примеры валидации данных. В обоих случаях ответ
422 Unprocessable Content
.
29 февраля у невисокосного 2025 года:/d/git/bankiru-dbapi (main) $ http GET $REVIEWS_ENDPOINT API-Token:$API_TOKEN \ > startDate==20250229 HTTP/1.1 422 Unprocessable Content content-length: 152 content-type: application/json date: Thu, 14 Aug 2025 08:09:14 GMT server: uvicorn { "detail": [ { "ctx": { "error": {} }, "input": "20250229", "loc": [ "query", "startDate" ], "msg": "Value error, day is out of range for month", "type": "value_error" } ] }
Неизвестный формат файла, для которого нет обработчика:
/d/git/bankiru-dbapi (main) $ http GET $REVIEWS_ENDPOINT API-Token:$API_TOKEN \ > outputFormat==abc HTTP/1.1 422 Unprocessable Content content-length: 197 content-type: application/json date: Thu, 14 Aug 2025 08:09:54 GMT server: uvicorn { "detail": [ { "ctx": { "expected": "'csv', 'json', 'parquet' or 'xlsx'" }, "input": "abc", "loc": [ "query", "outputFormat" ], "msg": "Input should be 'csv', 'json', 'parquet' or 'xlsx'", "type": "literal_error" } ] }
Здесь используется симпатичный мне подход “бесшовной валидации”. Новые обработчики, конвертирующие выборку из БД в тот или иной формат, пишутся как потомки базового абстрактного класса. В момент выполнения кода
inspect
формирует маппинг между расширением файла и соответствующим конвертером. Так, с одной стороны, определяется конвертер по указанному в запросе желаемому выходному формату. С другой — ключи этого маппинга, т.е. расширения, определяют значенияtyping.Literal
, который валидирует выходной формат в запросе. Так в запросе валидны только те форматы, для которых в коде существуют конвертеры. Если разработчик написал новый конвертер, то ничего дополнительно делать не нужно: соблюдение протокола базового класса сразу делает конвертер активным, а соответствующее расширение выходного файла — валидным значением в запросе.
- Как это может выглядеть в Pydantic Logfire. Это платформа с огромным функционалом для мониторинга, сбора и анализа телеметрии и логов приложений. Logfire выходит за рамки этого примера и упоминается здесь лишь для того чтобы привлечь ваше внимание к этому замечательному инструменту.
Pydantic Logfire project
- В конце несколько слов о Termius.
- защищенное подключение к хосту в один клик;
- хранение профилей и данных в зашифрованном хранилище, доступном со всех устройств, включая мобильные;
- личное и командное пространства;
- SFTP-клиент;
- сниппеты для быстрого запуска скриптов на всем прикрепленном парке хостов;
- режим синхронизации терминалов;
- автодополнения как в IDE;
- удобное управление ключами.
Termius SSH client
Last update: 2025-08-20, evm