Skip to content

Commit e7891c8

Browse files
committed
fixup! Convert branch state management to jobs
1 parent 1e622ab commit e7891c8

4 files changed

Lines changed: 35 additions & 15 deletions

File tree

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

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,10 @@
3434
"stop": BranchServiceStatus.STOPPING,
3535
}
3636

37-
_CONTROL_TRANSITION_FINAL: dict[str, BranchServiceStatus | None] = {
37+
_CONTROL_TRANSITION_FINAL: dict[str, BranchServiceStatus] = {
3838
"pause": BranchServiceStatus.PAUSED,
3939
"resume": BranchServiceStatus.STARTING,
40-
"start": None,
40+
"start": BranchServiceStatus.STARTING,
4141
"stop": BranchServiceStatus.STOPPED,
4242
}
4343

@@ -94,8 +94,7 @@ async def _async_perform_control(branch_id: str, action: str) -> dict:
9494
if branch is None:
9595
logger.error("Branch %s not found after control action %s", branch_id, action)
9696
return {"action": action}
97-
if final_status is not None:
98-
branch.set_status(final_status)
97+
branch.set_status(final_status)
9998
branch.control_task_id = None
10099
await session.commit()
101100

tests/branches/test_basic.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ def test_branch_resize(client, org, project, branch_id):
144144
wait_for_status(
145145
client,
146146
f"organizations/{org}/projects/{project}/branches/{branch_id}/",
147-
"ACTIVE_HEALTHY",
147+
["RESIZING", "ACTIVE_HEALTHY"],
148148
BRANCH_TIMEOUT_SEC,
149149
)
150150
r = client.get(f"organizations/{org}/projects/{project}/branches/{branch_id}/")

tests/branches/test_start_stop.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ def test_branch_stop(client, org, project, branch_id):
2626
wait_for_status(
2727
client,
2828
f"organizations/{org}/projects/{project}/branches/{branch_id}/",
29-
"STOPPED",
29+
["ACTIVE_HEALTHY", "STOPPING", "STOPPED"],
3030
BRANCH_TIMEOUT_SEC,
3131
)
3232

@@ -38,6 +38,6 @@ def test_branch_start(client, org, project, branch_id):
3838
wait_for_status(
3939
client,
4040
f"organizations/{org}/projects/{project}/branches/{branch_id}/",
41-
"ACTIVE_HEALTHY",
41+
["STOPPED", "STARTING", "ACTIVE_HEALTHY"],
4242
BRANCH_TIMEOUT_SEC,
4343
)

tests/conftest.py

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
VELA_KEYCLOAK_CLIENT_SECRET = os.getenv("VELA_KEYCLOAK_CLIENT_SECRET", "controller-secret")
1515
BRANCH_TIMEOUT_SEC = int(os.getenv("BRANCH_TIMEOUT_SEC", "900"))
1616

17-
_POLL_INTERVAL = 10
17+
_POLL_INTERVAL = 1
1818

1919

2020
class _KeycloakAuth(httpx.Auth):
@@ -51,20 +51,41 @@ def auth_flow(self, request: httpx.Request) -> Generator[httpx.Request, httpx.Re
5151
yield request
5252

5353

54-
def wait_for_status(client: httpx.Client, url: str, expected: str, timeout: int = BRANCH_TIMEOUT_SEC) -> dict:
55-
"""Poll GET url every 10s until response.json()["status"] == expected or timeout."""
54+
def wait_for_status(
55+
client: httpx.Client,
56+
url: str,
57+
expected: list[str],
58+
timeout: int = BRANCH_TIMEOUT_SEC,
59+
) -> dict:
60+
"""Poll GET url every 10s until the resource progresses through ``expected``.
61+
62+
``expected`` is an ordered list of statuses. Each status observed must
63+
appear at or after the current position in the list; going backward raises
64+
immediately. Statuses not in the list are treated as unknown intermediate
65+
states and ignored. ERROR always raises immediately. The final entry in
66+
``expected`` is the success condition.
67+
"""
5668
deadline = time.monotonic() + timeout
69+
idx = 0
70+
final = expected[-1]
5771
while True:
5872
r = client.get(url, timeout=30)
5973
r.raise_for_status()
6074
data = r.json()
6175
current = data.get("status")
62-
if current == expected:
63-
return data
6476
if current == "ERROR":
65-
raise RuntimeError(f"Resource entered ERROR state while waiting for status={expected!r}")
77+
raise RuntimeError(f"Resource entered ERROR state while waiting for status={final!r}")
78+
try:
79+
idx = expected.index(current, idx)
80+
except ValueError:
81+
if current in expected[:idx]:
82+
raise RuntimeError(f"Status {current!r} regressed; expected one of {expected[idx:]}") from None
83+
# Unknown intermediate state; keep waiting
84+
else:
85+
if current == final:
86+
return data
6687
if time.monotonic() >= deadline:
67-
raise TimeoutError(f"Timed out waiting for status={expected!r}; last status={current!r}")
88+
raise TimeoutError(f"Timed out waiting for status={final!r}; last status={current!r}")
6889
time.sleep(_POLL_INTERVAL)
6990

7091

@@ -152,7 +173,7 @@ def _factory(org_id: ULID, project_id: ULID, name: str, **overrides: object) ->
152173
wait_for_status(
153174
client,
154175
f"organizations/{org_id}/projects/{project_id}/branches/{uid}/",
155-
"ACTIVE_HEALTHY",
176+
["ACTIVE_HEALTHY"],
156177
BRANCH_TIMEOUT_SEC,
157178
)
158179
created.append((org_id, project_id, uid))

0 commit comments

Comments
 (0)