Оглавление
Введение
В Autoblocks мы используем Neon в качестве серверного поставщика Postgres для наших транзакционных данных. Поскольку мы постоянно работаем над улучшением нашего продукта на основе отзывов пользователей, мы часто вносим существенные изменения в схему нашей базы данных, чтобы наилучшим образом удовлетворить развивающиеся бизнес-потребности. Некоторые из этих миграций включают не только изменения схемы (добавление новой таблицы, столбца и т. д.), но также изменения данных, где мы пишем скрипты, например, для обновления столбцов, изменения схемы JSON-столбца, внесения разрушительных изменений без простоя и так далее.
Мы всегда тестируем такие изменения локально, но мы ценим дополнительное спокойствие, которое нам дает выполнение ”сухого” прогона на нашей производственной базе данных. До Neon для создания такой среды с использованием только RDS (сервиса реляционных баз данных от AWS) потребовалось бы значительные инженерные вложения. С Neon branching это удивительно легко — создать и уничтожить копии вашей производственной базы данных в среде непрерывной интеграции (CI).
В Autoblocks мы используем GitHub Actions, и мы сделали открытыми исходными кодами действия, которые мы написали для достижения этой цели.
Создание веток
Хотя действия поддерживают создание Neon веток для каждого коммита, мы решили создавать Neon ветку только в случае, когда есть миграции для выполнения. В нашем случае это происходит, когда наш каталог миграций Prisma был изменен. Наши миграции находятся в каталоге packages/db/prisma/migrations, а файл package.json в подкаталоге packages/db в нашем монорепо содержит скрипты для выполнения миграций:
"scripts": {
"migrate:dev": "prisma migrate dev",
"migrate:prod": "prisma migrate deploy"
}
GitHub Actions поддерживает фильтрацию по пути, но только на уровне рабочего процесса. Мы используем dorny/paths-filter, так как он позволяет нам добавлять фильтры по пути на уровне задачи. Вот сокращенный пример нашего основного рабочего процесса CI:
name: CI
on:
push:
branches-ignore:
- main
jobs:
changes:
runs-on: ubuntu-latest
outputs:
migrations: ${{ steps.changes.outputs.migrations }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- uses: dorny/paths-filter@v2
id: changes
with:
filters: |
migrations:
- 'packages/db/prisma/migrations/**'
validate-migrations:
needs: changes
if: needs.changes.outputs.migrations == 'true'
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
# Setup node, install dependencies, etc.
- name: Create Neon branch
uses: autoblocksai/neon-actions/create-branch@v1
id: neon
with:
api-key: ${{ secrets.NEON_API_KEY }}
project-id: ${{ vars.NEON_PROJECT_ID }}
- name: Run DB migrations
run: npm run migrate:prod
working-directory: packages/db
env:
DATABASE_URL: postgres://${{ secrets.PG_USERNAME }}:${{ secrets.PG_PASSWORD }}@${{ steps.neon.outputs.direct-host }}:5432/neondb
Теперь, когда я отправляю коммит в ветку GitHub, которая изменяет каталог миграций packages/db/prisma/migrations, мы:
- Создаем Neon ветку из последнего состояния нашей производственной базы данных.
- Запускаем наши миграции базы данных в этой ветке.
- Добавляем статус успешного/неуспешного выполнения к коммиту запроса на вливание.
Имя Neon ветки будет именем ветки GitHub плюс первыми семью символами SHA-хеша коммита: {branchName}-{commitSha}
Например, я создал ветку GitHub с именем add-new-table, изменил каталог миграций и затем отправил три коммита:

При каждом выполнении рабочего процесса CI будет создана новая Neon ветка, а затем на этой ветке будут запущены наши миграции. Ниже приведен пример вывода в консоли от действия autoblocksai/neon-actions/create-branch:
-> Run autoblocksai/neon-actions/create-branch@v1
Creating new branch with name 'add-new-table-d105eb3'
Created new branch:
{
"branch": {
"id": "br-empty-voice-99968957",
"project_id": "early-silence-295820",
"parent_id": "br-smelly-top-392940",
"name": "add-new-table-d105eb3",
"current_state": "init"
},
"endpoints": [
{
"id": "ep-bold-glade-26143287",
"host": "ep-bold-glade-26143287.us-east-1.aws.neon.tech",
"current_state": "init"
}
]
}
Notice: Your Neon branch is at <https://console.neon.tech/app/projects/early-silence-295820/branches/br-empty-voice-99968957>
Wating for branch br-empty-voice-99968957 to be ready
Retrying in 0.25 seconds (5 retries left)
Branch br-empty-voice-99968957 is ready!
Wating for endpoint ep-bold-glade-26143287 to be ready
Endpoint ep-bold-glade-26143287 is ready!
Direct host: ep-bold-glade-26143287.us-east-1.aws.neon.tech
Pooled host: ep-bold-glade-26143287-pooler.us-east-1.aws.neon.tech
ы заметите, что у нас есть два хоста на выбор: либо прямой хост, либо пул-хост. Они доступны как выводы из действия с именами direct-host и pooled-host соответственно. Мы используем прямое соединение для миграций, так как Prisma требует его, но вероятно, вы захотите использовать пул-соединение для любого другого типа соединения, например, из веб-приложения или набора тестов на производительность.
Удаление веток
Когда ветка GitHub удаляется, независимо от того, удаляется ли она напрямую или в результате слияния запроса на вливание, мы хотим удалить все Neon ветки, созданные из этой ветки. Для этого мы просто запускаем действие autoblocksai/neon-actions/delete-branches при событии delete:
`name: Delete Neon Branches
on: delete
jobs:
delete-neon-branches:
if: github.event.ref_type == 'branch'
runs-on: ubuntu-latest
steps:
- name: Delete Neon branches
uses: autoblocksai/neon-actions/delete-branches@v1
with:
api-key: ${{ secrets.NEON_API_KEY }}
project-id: ${{ vars.NEON_PROJECT_ID }}`
Это удалит все Neon ветки, имена которых начинаются с имени ветки GitHub, которая была только что удалена.
-> Run autoblocksai/neon-actions/delete-branches@v1
Found 3 branches:
add-new-table-d105eb3 (br-empty-voice-99968957)
add-new-table-9c62e5b (br-autumn-silence-26803864)
add-new-table-a58c909 (br-jolly-rice-40072094)
Deleting branches with prefix 'add-new-table-':
deleting add-new-table-d105eb3 (br-empty-voice-99968957)
deleting add-new-table-9c62e5b (br-autumn-silence-26803864)
deleting add-new-table-a58c909 (br-jolly-rice-40072094)
Больше примеров
Хотя мы используем Neon ветки только для проверки наших миграций, вы также можете использовать их в других контекстах, таких как тесты на производительность или среды предварительного просмотра Vercel. В таких случаях вы, вероятно, захотите отказаться от фильтрации по пути и затем использовать пул-хост в последующих шагах:
name: CI
on: push
jobs:
ci:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup node
uses: actions/setup-node@v3
- name: Install dependencies
run: npm ci
- name: Create neon branch
id: neon
uses: autoblocksai/neon-actions/create-branch@v1
with:
api-key: ${{ secrets.NEON_API_KEY }}
project-id: ${{ vars.NEON_PROJECT_ID }}
- name: Run prisma migrations
run: npx prisma migrate deploy
env:
DATABASE_URL: postgres://${{ secrets.PG_USERNAME }}:${{ secrets.PG_PASSWORD }}@${{ steps.neon.outputs.direct-host }}:5432/neondb
- name: Run smoke tests
run: npm run test:smoke
env:
DATABASE_URL: postgres://${{ secrets.PG_USERNAME }}:${{ secrets.PG_PASSWORD }}@${{ steps.neon.outputs.pooled-host }}:5432/neondb
См. документацию для получения дополнительных сведений.