Skip to content

Commit e5ad755

Browse files
committed
store the port in DB as part of _persist_branch_db_port instead of migration
1 parent ed25425 commit e5ad755

2 files changed

Lines changed: 13 additions & 113 deletions

File tree

src/api/organization/project/branch/__init__.py

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -158,18 +158,19 @@ async def _persist_branch_status(branch_id: Identifier, status: BranchServiceSta
158158
await session.commit()
159159

160160

161-
async def _persist_branch_db_port(branch_id: Identifier) -> None:
162-
port = await _resolve_branch_db_port(branch_id)
161+
async def _get_branch_db_port(branch: Branch) -> int:
162+
if branch.db_port is not None:
163+
return branch.db_port
164+
port = await _resolve_branch_db_port(branch.id)
163165
if port is None:
164-
logger.warning("Could not resolve db port for branch %s", branch_id)
165-
return
166+
raise VelaKubernetesError(f"Could not resolve db port for branch {branch.id}")
166167
async with AsyncSessionLocal() as session:
167-
branch = await session.get(Branch, branch_id)
168-
if branch is None:
169-
logger.warning("Branch %s missing while persisting db_port", branch_id)
170-
return
171-
branch.db_port = port
172-
await session.commit()
168+
db_branch = await session.get(Branch, branch.id)
169+
if db_branch is not None:
170+
db_branch.db_port = port
171+
await session.commit()
172+
branch.db_port = port
173+
return port
173174

174175

175176
async def _cleanup_failed_branch_deployment(branch_id: Identifier) -> None:
@@ -729,7 +730,6 @@ async def _deploy_branch_environment_task(
729730
branch_slug,
730731
)
731732
return
732-
await _persist_branch_db_port(branch_id)
733733
await _persist_branch_status(branch_id, BranchServiceStatus.STARTING)
734734

735735

@@ -803,7 +803,6 @@ async def _clone_branch_environment_task(
803803
branch_slug,
804804
)
805805
return
806-
await _persist_branch_db_port(branch_id)
807806
await _persist_branch_status(branch_id, BranchServiceStatus.STARTING)
808807

809808

@@ -884,7 +883,6 @@ async def _restore_branch_environment_task(
884883
branch_slug,
885884
)
886885
return
887-
await _persist_branch_db_port(branch_id)
888886
await _persist_branch_status(branch_id, BranchServiceStatus.STARTING)
889887

890888

@@ -1026,7 +1024,7 @@ async def _public(branch: Branch) -> BranchPublic:
10261024
project = await branch.awaitable_attrs.project
10271025

10281026
db_host = _resolve_db_host(branch) or ""
1029-
port = branch.db_port or (await _resolve_branch_db_port(branch.id)) or 0
1027+
port = await _get_branch_db_port(branch)
10301028

10311029
# pg-meta and pg are in the same network. So password is not required in connection string.
10321030
connection_string = _build_connection_string("vela", "postgres", 5432)

src/models/migrations/versions/2b4e8f1a6c03_branch_db_port.py

Lines changed: 1 addition & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -1,87 +1,21 @@
1-
"""Add and backfill branch.db_port
1+
"""Add branch.db_port
22
33
Revision ID: 2b4e8f1a6c03
44
Revises: f4f677e4e9b9
55
Create Date: 2026-03-19 00:00:00.000000
66
77
"""
8-
import logging
9-
import os
108
from typing import Sequence, Union
11-
from uuid import UUID
129

1310
from alembic import op
1411
import sqlalchemy as sa
15-
from kubernetes import client as kubernetes_client
16-
from kubernetes import config as kubernetes_config
17-
from kubernetes.config.config_exception import ConfigException
18-
from ulid import ULID
19-
20-
logger = logging.getLogger(__name__)
2112

2213
# revision identifiers, used by Alembic.
2314
revision: str = '2b4e8f1a6c03'
2415
down_revision: Union[str, Sequence[str], None] = 'a1b2c3d4e5f6'
2516
branch_labels: Union[str, Sequence[str], None] = None
2617
depends_on: Union[str, Sequence[str], None] = None
2718

28-
_CHART_NAME = "vela"
29-
30-
31-
def _ensure_kube_client_config() -> None:
32-
try:
33-
kubernetes_config.load_incluster_config()
34-
except ConfigException:
35-
try:
36-
kubernetes_config.load_kube_config()
37-
except ConfigException as exc:
38-
raise RuntimeError("Kubernetes client not configured. Mount kubeconfig or run in-cluster.") from exc
39-
40-
41-
def _uuid_to_ulid_str(uuid_str: str) -> str:
42-
"""Convert a UUID string (as stored in the DB) back to a ULID string."""
43-
return str(ULID.from_bytes(UUID(uuid_str).bytes))
44-
45-
46-
def _deployment_namespace(branch_id: str) -> str:
47-
prefix = os.environ.get("VELA_DEPLOYMENT_NAMESPACE_PREFIX", "vela")
48-
ulid_str = _uuid_to_ulid_str(branch_id).lower()
49-
return f"{prefix}-{ulid_str}" if prefix else ulid_str
50-
51-
52-
def _release_fullname() -> str:
53-
release = os.environ.get("VELA_DEPLOYMENT_RELEASE_NAME", "vela")
54-
return release if _CHART_NAME in release else f"{release}-{_CHART_NAME}"
55-
56-
57-
def _branch_service_name(component: str) -> str:
58-
return f"{_release_fullname()}-{component}"
59-
60-
61-
def _get_all_node_ports() -> dict[str, int]:
62-
"""Fetch node ports for all pgbouncer/db services in a single API call.
63-
64-
Returns a mapping of namespace -> nodePort, preferring the pgbouncer service
65-
over the db service when both exist in the same namespace.
66-
"""
67-
core_v1 = kubernetes_client.CoreV1Api()
68-
target_names = {_branch_service_name("pgbouncer"), _branch_service_name("db")}
69-
70-
svc_list = core_v1.list_service_for_all_namespaces()
71-
72-
ports_by_namespace: dict[str, int] = {}
73-
for svc in svc_list.items:
74-
if svc.metadata.name not in target_names:
75-
continue
76-
ns = svc.metadata.namespace
77-
if ns in ports_by_namespace:
78-
continue # already resolved for this namespace
79-
ports = svc.spec.ports
80-
if ports and ports[0].node_port:
81-
ports_by_namespace[ns] = ports[0].node_port
82-
83-
return ports_by_namespace
84-
8519

8620
def upgrade() -> None:
8721
"""Upgrade schema."""
@@ -90,38 +24,6 @@ def upgrade() -> None:
9024
sa.Column('db_port', sa.Integer(), nullable=True),
9125
)
9226

93-
bind = op.get_bind()
94-
branch_rows = bind.execute(
95-
sa.text("SELECT id::text AS id FROM branch")
96-
).mappings().all()
97-
98-
if not branch_rows:
99-
return
100-
101-
_ensure_kube_client_config()
102-
ports_by_namespace = _get_all_node_ports()
103-
104-
updates = []
105-
for row in branch_rows:
106-
namespace = _deployment_namespace(row["id"])
107-
port = ports_by_namespace.get(namespace)
108-
if port is None:
109-
logger.warning("Could not resolve db_port for branch %s — skipping", row["id"])
110-
continue
111-
updates.append({"id": row["id"], "db_port": port})
112-
113-
if updates:
114-
bind.execute(
115-
sa.text(
116-
"""
117-
UPDATE branch
118-
SET db_port = :db_port
119-
WHERE id = CAST(:id AS uuid)
120-
"""
121-
),
122-
updates,
123-
)
124-
12527

12628
def downgrade() -> None:
12729
"""Downgrade schema."""

0 commit comments

Comments
 (0)