Skip to content

Commit b69c026

Browse files
authored
Merge pull request #1459 from transformerlab/fix/improve-live-status-remote-trap
Set Job to RUNNING when remote trap starts and introduce a lab_init live status
2 parents 0efb08f + da28eb1 commit b69c026

7 files changed

Lines changed: 70 additions & 10 deletions

File tree

api/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ dependencies = [
3333
"soundfile==0.13.1",
3434
"tensorboardX==2.6.2.2",
3535
"timm==1.0.15",
36-
"transformerlab==0.0.90",
36+
"transformerlab==0.0.91",
3737
"transformerlab-inference==0.2.52",
3838
"transformers==4.57.1",
3939
"wandb==0.23.1",

api/transformerlab/routers/compute_provider.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1862,8 +1862,8 @@ async def check_provider_job_status(
18621862
"launch_progress": launch_progress,
18631863
}
18641864

1865-
# Only check provider status for jobs in LAUNCHING state
1866-
if job_status != "LAUNCHING":
1865+
# Only check provider status for jobs that are still launching or running
1866+
if job_status not in ("LAUNCHING", "RUNNING"):
18671867
return {
18681868
"status": "success",
18691869
"job_id": job_id,

lab-sdk/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "transformerlab"
7-
version = "0.0.90"
7+
version = "0.0.91"
88
description = "Python SDK for Transformer Lab"
99
readme = "README.md"
1010
requires-python = ">=3.10"

lab-sdk/src/lab/lab_facade.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,17 @@ def init(self, experiment_id: str | None = None, config: Optional[Dict[str, Any]
117117
# Update status to RUNNING for both cases
118118
_run_async(self._job.update_status("RUNNING"))
119119

120+
# Best-effort marker so UIs can distinguish jobs where lab has been
121+
# explicitly initialized. This reuses the existing live_status field
122+
# that remote_trap also writes to (started/finished/crashed). Depending
123+
# on ordering, live_status may briefly be "lab_init" before or after
124+
# "started" is set by tfl-remote-trap.
125+
try:
126+
_run_async(self._job.update_job_data_field("live_status", "lab_init"))
127+
except Exception:
128+
# Never let status marker failures break user code.
129+
logger.debug("Failed to set live_status=lab_init on job", exc_info=True)
130+
120131
# Check for wandb integration and capture URL if available
121132
self._detect_and_capture_wandb_url()
122133

lab-sdk/src/lab/remote_trap.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,18 @@ async def _set_live_status_async(job_id: str, status: str) -> None:
2525
return
2626

2727

28+
async def _set_status_async(job_id: str, status: str) -> None:
29+
"""Async helper to set the high-level job status."""
30+
try:
31+
job = await Job.get(job_id)
32+
if job is None:
33+
return
34+
await job.update_status(status)
35+
except Exception:
36+
# This helper should never cause the wrapped command to fail.
37+
return
38+
39+
2840
def _set_live_status(status: str) -> None:
2941
"""Set live_status on the current remote job, if _TFL_JOB_ID is available."""
3042
job_id = os.environ.get("_TFL_JOB_ID")
@@ -47,6 +59,26 @@ def _set_live_status(status: str) -> None:
4759
return
4860

4961

62+
def _set_status(status: str) -> None:
63+
"""Set high-level job status for the current remote job, if _TFL_JOB_ID is available."""
64+
job_id = os.environ.get("_TFL_JOB_ID")
65+
if not job_id:
66+
return
67+
68+
try:
69+
asyncio.run(_set_status_async(job_id, status))
70+
except RuntimeError:
71+
# Fallback in case an event loop already exists.
72+
try:
73+
loop = asyncio.get_event_loop()
74+
if loop.is_running():
75+
loop.create_task(_set_status_async(job_id, status))
76+
else:
77+
loop.run_until_complete(_set_status_async(job_id, status))
78+
except Exception:
79+
return
80+
81+
5082
async def _write_provider_logs_async(job_id: str, logs_text: str) -> None:
5183
"""
5284
Best-effort helper to write combined stdout/stderr logs to the job directory.
@@ -124,6 +156,7 @@ def main(argv: List[str] | None = None) -> int:
124156

125157
# Mark job as started.
126158
_set_live_status("started")
159+
_set_status("RUNNING")
127160

128161
# Run the original command in the shell so it behaves exactly as submitted.
129162
# Capture stdout/stderr so we can save a copy to provider_logs.txt while still

src/renderer/components/Experiment/Tasks/JobProgress.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,14 @@ export default function JobProgress({
122122
const liveStatus = job?.job_data?.live_status;
123123
if (!liveStatus) return null;
124124

125+
if (liveStatus === 'lab_init') {
126+
return (
127+
<Typography level="body-xs" color="neutral">
128+
Lab instance initialized inside remote job.
129+
</Typography>
130+
);
131+
}
132+
125133
if (liveStatus === 'started') {
126134
return (
127135
<Typography level="body-xs" color="neutral">

src/renderer/components/Experiment/Tasks/Tasks.tsx

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -308,8 +308,12 @@ export default function Tasks({ subtype }: { subtype?: string }) {
308308
return false;
309309
}
310310

311-
// Always check LAUNCHING and WAITING jobs (for launch progress)
312-
if (job.status === 'LAUNCHING' || job.status === 'WAITING') {
311+
// Always check LAUNCHING, RUNNING, and WAITING jobs (for launch progress and live status)
312+
if (
313+
job.status === 'LAUNCHING' ||
314+
job.status === 'RUNNING' ||
315+
job.status === 'WAITING'
316+
) {
313317
return true;
314318
}
315319

@@ -356,11 +360,15 @@ export default function Tasks({ subtype }: { subtype?: string }) {
356360
}
357361
};
358362

359-
// Check immediately and then every 2s when there are LAUNCHING/WAITING jobs (for progress), else 10s
360-
const hasLaunching = jobsToCheck.some(
361-
(j: any) => j.status === 'LAUNCHING' || j.status === 'WAITING',
363+
// Check immediately and then every 2s when there are active jobs (LAUNCHING/RUNNING/WAITING),
364+
// else every 10s (mainly for recent COMPLETE jobs to ensure quota is recorded).
365+
const hasActiveRemoteJobs = jobsToCheck.some(
366+
(j: any) =>
367+
j.status === 'LAUNCHING' ||
368+
j.status === 'RUNNING' ||
369+
j.status === 'WAITING',
362370
);
363-
const intervalMs = hasLaunching ? 2000 : 10000;
371+
const intervalMs = hasActiveRemoteJobs ? 2000 : 10000;
364372
checkJobs();
365373
const interval = setInterval(checkJobs, intervalMs);
366374

0 commit comments

Comments
 (0)