Skip to content

Commit 199755b

Browse files
authored
Update VastAIAPIClient (#4038)
- Use a timeout in all requests to avoid requests hanging indefinitely. - Switch from URL-based to header-based auth token, which is the authentication method currently advertised in Vast.ai API docs.
1 parent 5b12312 commit 199755b

1 file changed

Lines changed: 14 additions & 14 deletions

File tree

src/dstack/_internal/core/backends/vastai/api_client.py

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1+
import json
12
from typing import Optional, Union
23

3-
import requests
4+
import httpx
45

56
import dstack._internal.utils.docker as docker
67
from dstack._internal.core.consts import DSTACK_RUNNER_SSH_PORT
@@ -31,9 +32,11 @@ def __init__(
3132

3233
class VastAIAPIClient:
3334
def __init__(self, api_key: str):
34-
self.api_url = "https://console.vast.ai/api"
35-
self.api_key = api_key
36-
self.s = requests.Session() # TODO: set adequate timeout everywhere the session is used
35+
self.s = httpx.Client(
36+
base_url="https://console.vast.ai/api/",
37+
headers={"Authorization": f"Bearer {api_key}"},
38+
timeout=30,
39+
)
3740

3841
def create_instance(
3942
self,
@@ -86,10 +89,10 @@ def create_instance(
8689
"create_from": None,
8790
"force": False,
8891
}
89-
resp = self.s.put(self._url(f"/v0/asks/{bundle_id}/"), json=payload)
92+
resp = self.s.put(f"/v0/asks/{bundle_id}/", json=payload)
9093
try:
9194
data = resp.json()
92-
except requests.exceptions.JSONDecodeError:
95+
except json.JSONDecodeError:
9396
raise VastAICreateInstanceError(resp=resp.text)
9497
if resp.status_code != 200 or not data["success"]:
9598
raise VastAICreateInstanceError(
@@ -98,19 +101,19 @@ def create_instance(
98101
return data["new_contract"]
99102

100103
def destroy_instance(self, instance_id: Union[str, int]) -> None:
101-
resp = self.s.delete(self._url(f"/v0/instances/{instance_id}/"))
104+
resp = self.s.delete(f"/v0/instances/{instance_id}/")
102105
if resp.status_code == 429:
103106
raise VastAIRateLimitError()
104107
try:
105108
data = resp.json()
106-
except requests.exceptions.JSONDecodeError:
109+
except json.JSONDecodeError:
107110
raise ComputeError(resp.text)
108111
if resp.status_code != 200 or not data["success"]:
109112
if data.get("error") != "no_such_instance":
110113
raise ComputeError(resp.text)
111114

112115
def get_instance(self, instance_id: Union[str, int]) -> Optional[dict]:
113-
resp = self.s.get(self._url(f"/v0/instances/{instance_id}/"))
116+
resp = self.s.get(f"/v0/instances/{instance_id}/")
114117
if resp.status_code == 429:
115118
raise VastAIRateLimitError()
116119
resp.raise_for_status()
@@ -119,10 +122,7 @@ def get_instance(self, instance_id: Union[str, int]) -> Optional[dict]:
119122

120123
def auth_test(self) -> bool:
121124
try:
122-
self.s.get(self._url("/v1/instances/")).raise_for_status()
125+
self.s.get("/v1/instances/").raise_for_status()
123126
return True
124-
except requests.HTTPError:
127+
except httpx.HTTPError:
125128
return False
126-
127-
def _url(self, path):
128-
return f"{self.api_url}/{path.lstrip('/')}?api_key={self.api_key}"

0 commit comments

Comments
 (0)