truss 0.11.9rc5__py3-none-any.whl → 0.11.9rc500__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of truss might be problematic. Click here for more details.
- truss/cli/logs/base_watcher.py +31 -12
- truss/cli/logs/model_log_watcher.py +24 -1
- truss/templates/control/control/application.py +2 -3
- truss/templates/control/control/helpers/truss_patch/model_container_patch_applier.py +7 -14
- truss/tests/templates/control/control/test_server.py +1 -1
- truss/util/__init__.py +0 -0
- {truss-0.11.9rc5.dist-info → truss-0.11.9rc500.dist-info}/METADATA +1 -1
- {truss-0.11.9rc5.dist-info → truss-0.11.9rc500.dist-info}/RECORD +11 -10
- {truss-0.11.9rc5.dist-info → truss-0.11.9rc500.dist-info}/WHEEL +0 -0
- {truss-0.11.9rc5.dist-info → truss-0.11.9rc500.dist-info}/entry_points.txt +0 -0
- {truss-0.11.9rc5.dist-info → truss-0.11.9rc500.dist-info}/licenses/LICENSE +0 -0
truss/cli/logs/base_watcher.py
CHANGED
|
@@ -17,7 +17,9 @@ class LogWatcher(ABC):
|
|
|
17
17
|
# NB(nikhil): we add buffer for clock skew, so this helps us detect duplicates.
|
|
18
18
|
# TODO(nikhil): clean up hashes so this doesn't grow indefinitely.
|
|
19
19
|
_log_hashes: set[str] = set()
|
|
20
|
-
|
|
20
|
+
|
|
21
|
+
_last_poll_time_ms: Optional[int] = None
|
|
22
|
+
_last_log_time_ms: Optional[int] = None
|
|
21
23
|
|
|
22
24
|
def __init__(self, api: BasetenApi):
|
|
23
25
|
self.api = api
|
|
@@ -26,37 +28,54 @@ class LogWatcher(ABC):
|
|
|
26
28
|
log_str = f"{log.timestamp}-{log.message}-{log.replica}"
|
|
27
29
|
return hashlib.sha256(log_str.encode("utf-8")).hexdigest()
|
|
28
30
|
|
|
29
|
-
def
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
def get_start_epoch_ms(self, now_ms: int) -> Optional[int]:
|
|
32
|
+
if self._last_poll_time_ms:
|
|
33
|
+
return self._last_poll_time_ms - CLOCK_SKEW_BUFFER_MS
|
|
34
|
+
|
|
35
|
+
return None
|
|
34
36
|
|
|
37
|
+
def fetch_and_parse_logs(
|
|
38
|
+
self, start_epoch_millis: Optional[int], end_epoch_millis: Optional[int]
|
|
39
|
+
) -> Iterator[ParsedLog]:
|
|
35
40
|
api_logs = self.fetch_logs(
|
|
36
|
-
start_epoch_millis=
|
|
41
|
+
start_epoch_millis=start_epoch_millis, end_epoch_millis=end_epoch_millis
|
|
37
42
|
)
|
|
38
43
|
|
|
39
44
|
parsed_logs = parse_logs(api_logs)
|
|
45
|
+
|
|
40
46
|
for log in parsed_logs:
|
|
41
|
-
h
|
|
42
|
-
if h not in self._log_hashes:
|
|
47
|
+
if (h := self._hash_log(log)) not in self._log_hashes:
|
|
43
48
|
self._log_hashes.add(h)
|
|
49
|
+
|
|
44
50
|
yield log
|
|
45
51
|
|
|
46
|
-
|
|
52
|
+
def poll(self) -> Iterator[ParsedLog]:
|
|
53
|
+
now_ms = int(time.time() * 1000)
|
|
54
|
+
start_epoch_ms = self.get_start_epoch_ms(now_ms)
|
|
55
|
+
|
|
56
|
+
for log in self.fetch_and_parse_logs(
|
|
57
|
+
start_epoch_millis=start_epoch_ms,
|
|
58
|
+
end_epoch_millis=now_ms + CLOCK_SKEW_BUFFER_MS,
|
|
59
|
+
):
|
|
60
|
+
yield log
|
|
61
|
+
|
|
62
|
+
epoch_ns = int(log.timestamp)
|
|
63
|
+
self._last_log_time_ms = int(epoch_ns / 1e6)
|
|
64
|
+
|
|
65
|
+
self._last_poll_time_ms = now_ms
|
|
47
66
|
|
|
48
67
|
def watch(self) -> Iterator[ParsedLog]:
|
|
49
68
|
self.before_polling()
|
|
50
69
|
with console.status("Polling logs", spinner="aesthetic"):
|
|
51
70
|
while True:
|
|
52
|
-
for log in self.
|
|
71
|
+
for log in self.poll():
|
|
53
72
|
yield log
|
|
54
73
|
if self._log_hashes:
|
|
55
74
|
break
|
|
56
75
|
time.sleep(POLL_INTERVAL_SEC)
|
|
57
76
|
|
|
58
77
|
while self.should_poll_again():
|
|
59
|
-
for log in self.
|
|
78
|
+
for log in self.poll():
|
|
60
79
|
yield log
|
|
61
80
|
time.sleep(POLL_INTERVAL_SEC)
|
|
62
81
|
self.post_poll()
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
+
from functools import cached_property
|
|
1
2
|
from typing import Any, List, Optional
|
|
2
3
|
|
|
3
4
|
from truss.cli.logs.base_watcher import LogWatcher
|
|
4
5
|
from truss.remote.baseten.api import BasetenApi
|
|
5
6
|
from truss.remote.baseten.utils.status import MODEL_RUNNING_STATES
|
|
6
7
|
|
|
8
|
+
MAX_LOOK_BACK_MS = 1000 * 60 * 60 # 1 hour.
|
|
9
|
+
|
|
7
10
|
|
|
8
11
|
class ModelDeploymentLogWatcher(LogWatcher):
|
|
9
12
|
_model_id: str
|
|
@@ -25,11 +28,31 @@ class ModelDeploymentLogWatcher(LogWatcher):
|
|
|
25
28
|
self._model_id, self._deployment_id, start_epoch_millis, end_epoch_millis
|
|
26
29
|
)
|
|
27
30
|
|
|
31
|
+
def get_start_epoch_ms(self, now_ms: int) -> Optional[int]:
|
|
32
|
+
# NOTE(Tyron): If there can be multiple replicas,
|
|
33
|
+
# we can't use a timestamp cursor to poll for logs.
|
|
34
|
+
if not self._is_development:
|
|
35
|
+
return super().get_start_epoch_ms(now_ms)
|
|
36
|
+
|
|
37
|
+
# Cursor logic.
|
|
38
|
+
|
|
39
|
+
if self._last_log_time_ms:
|
|
40
|
+
return max(self._last_log_time_ms, now_ms - MAX_LOOK_BACK_MS)
|
|
41
|
+
|
|
42
|
+
return None
|
|
43
|
+
|
|
28
44
|
def should_poll_again(self) -> bool:
|
|
29
45
|
return self._current_status in MODEL_RUNNING_STATES
|
|
30
46
|
|
|
47
|
+
def _get_deployment(self) -> Any:
|
|
48
|
+
return self.api.get_deployment(self._model_id, self._deployment_id)
|
|
49
|
+
|
|
31
50
|
def _get_current_status(self) -> str:
|
|
32
|
-
return self.
|
|
51
|
+
return self._get_deployment()["status"]
|
|
52
|
+
|
|
53
|
+
@cached_property
|
|
54
|
+
def _is_development(self) -> bool:
|
|
55
|
+
return self._get_deployment()["is_development"]
|
|
33
56
|
|
|
34
57
|
def post_poll(self) -> None:
|
|
35
58
|
self._current_status = self._get_current_status()
|
|
@@ -84,10 +84,9 @@ def create_app(base_config: Dict):
|
|
|
84
84
|
base_url=f"http://localhost:{app_state.inference_server_port}", limits=limits
|
|
85
85
|
)
|
|
86
86
|
|
|
87
|
-
|
|
88
|
-
|
|
87
|
+
uv_path = getattr(app_state, "uv_path", None)
|
|
89
88
|
patch_applier = ModelContainerPatchApplier(
|
|
90
|
-
Path(app_state.inference_server_home), app_logger,
|
|
89
|
+
Path(app_state.inference_server_home), app_logger, uv_path
|
|
91
90
|
)
|
|
92
91
|
|
|
93
92
|
oversee_inference_server = getattr(app_state, "oversee_inference_server", True)
|
|
@@ -22,8 +22,6 @@ from helpers.truss_patch.model_code_patch_applier import apply_code_patch
|
|
|
22
22
|
from truss.base.truss_config import ExternalData, ExternalDataItem, TrussConfig
|
|
23
23
|
from truss.util.download import download_external_data
|
|
24
24
|
|
|
25
|
-
DEFAULT_PYTHON_EXECUTABLE = "python3"
|
|
26
|
-
|
|
27
25
|
|
|
28
26
|
class ModelContainerPatchApplier:
|
|
29
27
|
"""Applies patches to container running a truss.
|
|
@@ -49,10 +47,12 @@ class ModelContainerPatchApplier:
|
|
|
49
47
|
if uv_path is not None:
|
|
50
48
|
self._uv_path_cached = uv_path
|
|
51
49
|
|
|
52
|
-
# NB(nikhil): Get full path to the python interpreter for pip patches.
|
|
53
50
|
self._python_executable = self._get_python_executable()
|
|
54
51
|
|
|
55
52
|
def _get_python_executable(self) -> str:
|
|
53
|
+
# NB(nikhil): `uv` requires the full path to the python interpreter for patching
|
|
54
|
+
# python modules. We expect PYTHON_EXECUTABLE to exist in all development images, but
|
|
55
|
+
# we fallback to python3 as a default.
|
|
56
56
|
python_executable = os.environ.get("PYTHON_EXECUTABLE", "python3")
|
|
57
57
|
full_executable_path = shutil.which(python_executable)
|
|
58
58
|
return full_executable_path or python_executable
|
|
@@ -111,7 +111,6 @@ class ModelContainerPatchApplier:
|
|
|
111
111
|
"pip",
|
|
112
112
|
"uninstall",
|
|
113
113
|
python_requirement_patch.requirement,
|
|
114
|
-
"--yes",
|
|
115
114
|
"--python",
|
|
116
115
|
self._python_executable,
|
|
117
116
|
],
|
|
@@ -177,14 +176,8 @@ class ModelContainerPatchApplier:
|
|
|
177
176
|
|
|
178
177
|
|
|
179
178
|
def _identify_uv_path() -> str:
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
Path.home() / ".cargo" / "bin" / "uv",
|
|
184
|
-
]
|
|
185
|
-
|
|
186
|
-
for path in candidate_paths:
|
|
187
|
-
if path.exists():
|
|
188
|
-
return str(path)
|
|
179
|
+
uv_path = shutil.which("uv")
|
|
180
|
+
if not uv_path:
|
|
181
|
+
raise RuntimeError("Unable to find `uv`, make sure it's installed.")
|
|
189
182
|
|
|
190
|
-
|
|
183
|
+
return uv_path
|
|
@@ -53,7 +53,7 @@ def app(truss_container_fs, truss_original_hash, ports):
|
|
|
53
53
|
"control_server_port": ports["control_server_port"],
|
|
54
54
|
"inference_server_port": ports["inference_server_port"],
|
|
55
55
|
"oversee_inference_server": False,
|
|
56
|
-
"
|
|
56
|
+
"uv_path": "uv",
|
|
57
57
|
}
|
|
58
58
|
)
|
|
59
59
|
inference_server_controller = control_app.state.inference_server_controller
|
truss/util/__init__.py
ADDED
|
File without changes
|
|
@@ -12,8 +12,8 @@ truss/cli/chains_commands.py,sha256=Kpa5mCg6URAJQE2ZmZfVQFhjBHEitKT28tKiW0H6XAI,
|
|
|
12
12
|
truss/cli/cli.py,sha256=PaMkuwXZflkU7sa1tEoT_Zmy-iBkEZs1m4IVqcieaeo,30367
|
|
13
13
|
truss/cli/remote_cli.py,sha256=G_xCKRXzgkCmkiZJhUFfsv5YSVgde1jLA5LPQitpZgI,1905
|
|
14
14
|
truss/cli/train_commands.py,sha256=Cfr9-TDE-esQI_R8az5OpLoQyz3Qv38mLsSNwy9znmI,18873
|
|
15
|
-
truss/cli/logs/base_watcher.py,sha256=
|
|
16
|
-
truss/cli/logs/model_log_watcher.py,sha256=
|
|
15
|
+
truss/cli/logs/base_watcher.py,sha256=vuqteoaMVGX34cgKcETf4X_gOkvnSnDaWz1_pbeFhqs,3343
|
|
16
|
+
truss/cli/logs/model_log_watcher.py,sha256=38vQCcNItfDrTKucvdJ10ZYLOcbGa5ZAKUqUnV4nH34,1971
|
|
17
17
|
truss/cli/logs/training_log_watcher.py,sha256=r6HRqrLnz-PiKTUXiDYYxg4ZnP8vYcXlEX1YmgHhzlo,1173
|
|
18
18
|
truss/cli/logs/utils.py,sha256=z-U_FG4BUzdZLbE3BnXb4DZQ0zt3LSZ3PiQpLaDuc3o,1031
|
|
19
19
|
truss/cli/train/common.py,sha256=xTR41U5FeSndXfNBBHF9wF5XwZH1sOIVFlv-XHjsKIU,1547
|
|
@@ -73,7 +73,7 @@ truss/templates/copy_cache_files.Dockerfile.jinja,sha256=Os5zFdYLZ_AfCRGq4RcpVTO
|
|
|
73
73
|
truss/templates/docker_server_requirements.txt,sha256=PyhOPKAmKW1N2vLvTfLMwsEtuGpoRrbWuNo7tT6v2Mc,18
|
|
74
74
|
truss/templates/server.Dockerfile.jinja,sha256=CUYnF_hgxPGq2re7__0UPWlwzOHMoFkxp6NVKi3U16s,7071
|
|
75
75
|
truss/templates/control/requirements.txt,sha256=nqqNmlTwFeV8sV4fqwItwzzd_egADBP_e-cEopXBJ4k,358
|
|
76
|
-
truss/templates/control/control/application.py,sha256=
|
|
76
|
+
truss/templates/control/control/application.py,sha256=GxjRglKQhug0bOJEeBcj9YJWJzHVAnAybvgzDcopG5k,5122
|
|
77
77
|
truss/templates/control/control/endpoints.py,sha256=KzqsLVNJE6r6TCPW8D5FMCtsfHadTwR15A3z_viGxmM,11782
|
|
78
78
|
truss/templates/control/control/server.py,sha256=R4Y219i1dcz0kkksN8obLoX-YXWGo9iW1igindyG50c,3128
|
|
79
79
|
truss/templates/control/control/helpers/context_managers.py,sha256=W6dyFgLBhPa5meqrOb3w_phMtKfaJI-GhwUfpiycDc8,413
|
|
@@ -84,7 +84,7 @@ truss/templates/control/control/helpers/inference_server_process_controller.py,s
|
|
|
84
84
|
truss/templates/control/control/helpers/inference_server_starter.py,sha256=Fz2Puijro6Cc5cvTsAqOveNJbBQR_ARYJXl4lvETJ8Y,2633
|
|
85
85
|
truss/templates/control/control/helpers/truss_patch/__init__.py,sha256=CXZdUV_ylqLTJrKuFpvSnUT6PUFrZrMF2y6jiHbdaKU,998
|
|
86
86
|
truss/templates/control/control/helpers/truss_patch/model_code_patch_applier.py,sha256=LTIIADLz0wRn7V49j64dU1U7Hbta9YLde3pb5YZWvzQ,2001
|
|
87
|
-
truss/templates/control/control/helpers/truss_patch/model_container_patch_applier.py,sha256=
|
|
87
|
+
truss/templates/control/control/helpers/truss_patch/model_container_patch_applier.py,sha256=9bWoleD_dfQHokW5qgC5DyvAQPVhSku3tUqrVKQsQ3w,7091
|
|
88
88
|
truss/templates/control/control/helpers/truss_patch/requirement_name_identifier.py,sha256=CL3KEAj4B3ApMQShd7TI5umXVbazLZY5StrNlwHwWtc,1995
|
|
89
89
|
truss/templates/control/control/helpers/truss_patch/system_packages.py,sha256=IYh1CVU_kooAvtSGXKQDDWnNdOhlv7ENWagsL1wvhgw,208
|
|
90
90
|
truss/templates/custom/examples.yaml,sha256=2UcCtEdavImWmiCtj31ckBlAKVOwNMC5AwMIIznKDag,48
|
|
@@ -166,7 +166,7 @@ truss/tests/remote/baseten/test_remote.py,sha256=y1qSPL1t7dBeYI3xMFn436fttG7wkYd
|
|
|
166
166
|
truss/tests/remote/baseten/test_service.py,sha256=ufZbtQlBNIzFCxRt_iE-APLpWbVw_3ViUpSh6H9W5nU,1945
|
|
167
167
|
truss/tests/templates/control/control/conftest.py,sha256=euDFh0AhcHP-vAmTzi1Qj3lymnplDTgvtbt4Ez_lfpw,654
|
|
168
168
|
truss/tests/templates/control/control/test_endpoints.py,sha256=HIlRYOicsdHD8r_V5gHpZWybDC26uwXJfbvCohdE3HI,3751
|
|
169
|
-
truss/tests/templates/control/control/test_server.py,sha256=
|
|
169
|
+
truss/tests/templates/control/control/test_server.py,sha256=0D0OMwZ-9jZRxxHoiQYij0RBMenuA9o29LlwNzd04Vk,9149
|
|
170
170
|
truss/tests/templates/control/control/test_server_integration.py,sha256=kvhgN1OGF5SZ1JFeg6qwbcrTy-Vr7B2JSP2z507ahxo,11925
|
|
171
171
|
truss/tests/templates/control/control/helpers/test_context_managers.py,sha256=3LoonRaKu_UvhaWs1eNmEQCZq-iJ3aIjI0Mn4amC8Bw,283
|
|
172
172
|
truss/tests/templates/control/control/helpers/test_model_container_patch_applier.py,sha256=jhPgExGFF42iuWPM9ry93dnpF765d-CGTCIhbswK0hk,5730
|
|
@@ -335,6 +335,7 @@ truss/truss_handle/patch/local_truss_patch_applier.py,sha256=fOHWKt3teYnbqeRsF63
|
|
|
335
335
|
truss/truss_handle/patch/signature.py,sha256=8eas8gy6Japd1hrgdmtHmKTTxQmWsbmgKRQQGL2PVuA,858
|
|
336
336
|
truss/truss_handle/patch/truss_dir_patch_applier.py,sha256=uhhHvKYHn_dpfz0xp4jwO9_qAej5sO3f8of_h-21PP4,3666
|
|
337
337
|
truss/util/.truss_ignore,sha256=jpQA9ou-r_JEIcEHsUqGLHhir_m3d4IPGNyzKXtS-2g,3131
|
|
338
|
+
truss/util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
338
339
|
truss/util/docker.py,sha256=6PD7kMBBrOjsdvgkuSv7JMgZbe3NoJIeGasljMm2SwA,3934
|
|
339
340
|
truss/util/download.py,sha256=1lfBwzyaNLEp7SAVrBd9BX5inZpkCVp8sBnS9RNoiJA,2521
|
|
340
341
|
truss/util/env_vars.py,sha256=7Bv686eER71Barrs6fNamk_TrTJGmu9yV2TxaVmupn0,1232
|
|
@@ -369,8 +370,8 @@ truss_train/deployment.py,sha256=lWWANSuzBWu2M4oK4qD7n-oVR1JKdmw2Pn5BJQHg-Ck,307
|
|
|
369
370
|
truss_train/loader.py,sha256=0o66EjBaHc2YY4syxxHVR4ordJWs13lNXnKjKq2wq0U,1630
|
|
370
371
|
truss_train/public_api.py,sha256=9N_NstiUlmBuLUwH_fNG_1x7OhGCytZLNvqKXBlStrM,1220
|
|
371
372
|
truss_train/restore_from_checkpoint.py,sha256=8hdPm-WSgkt74HDPjvCjZMBpvA9MwtoYsxVjOoa7BaM,1176
|
|
372
|
-
truss-0.11.
|
|
373
|
-
truss-0.11.
|
|
374
|
-
truss-0.11.
|
|
375
|
-
truss-0.11.
|
|
376
|
-
truss-0.11.
|
|
373
|
+
truss-0.11.9rc500.dist-info/METADATA,sha256=eNLITceNhpjLM8bGpJAOq_cBWJEPzg02P9H60QHx1uw,6682
|
|
374
|
+
truss-0.11.9rc500.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
375
|
+
truss-0.11.9rc500.dist-info/entry_points.txt,sha256=-MwKfHHQHQ6j0HqIgvxrz3CehCmczDLTD-OsRHnjjuU,130
|
|
376
|
+
truss-0.11.9rc500.dist-info/licenses/LICENSE,sha256=FTqGzu85i-uw1Gi8E_o0oD60bH9yQ_XIGtZbA1QUYiw,1064
|
|
377
|
+
truss-0.11.9rc500.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|