mirror of
https://github.com/Stone-Red-Code/dvc.git
synced 2026-11-02 07:18:25 +01:00
Use celery status as the exp show status
fix: #8349 `tasks status turned to queued for 1 second before turned into success.` is because in previous the status is using the output of `get_running_exps` in `repo.expereiments` and when entering the collect result progress, the `get_running_exps` will mark the tasks to be not running because the `info.result` is not None. Here we use the output of the celery queue as the universal standard for the tasks status. 1. Use celery status as the exp show status
This commit is contained in:
@@ -468,11 +468,11 @@ class Experiments:
|
|||||||
info = ExecutorInfo.from_dict(load_json(infofile))
|
info = ExecutorInfo.from_dict(load_json(infofile))
|
||||||
except OSError:
|
except OSError:
|
||||||
return result
|
return result
|
||||||
if info.result is None:
|
if info.status < TaskStatus.FAILED:
|
||||||
if rev == "workspace":
|
if rev == "workspace":
|
||||||
# If we are appending to a checkpoint branch in a workspace
|
# If we are appending to a checkpoint branch in a workspace
|
||||||
# run, show the latest checkpoint as running.
|
# run, show the latest checkpoint as running.
|
||||||
if info.status > TaskStatus.RUNNING:
|
if info.status == TaskStatus.SUCCESS:
|
||||||
return result
|
return result
|
||||||
last_rev = self.scm.get_ref(EXEC_BRANCH)
|
last_rev = self.scm.get_ref(EXEC_BRANCH)
|
||||||
if last_rev:
|
if last_rev:
|
||||||
@@ -481,7 +481,11 @@ class Experiments:
|
|||||||
result[rev] = info.asdict()
|
result[rev] = info.asdict()
|
||||||
else:
|
else:
|
||||||
result[rev] = info.asdict()
|
result[rev] = info.asdict()
|
||||||
if info.git_url and fetch_refs:
|
if (
|
||||||
|
info.git_url
|
||||||
|
and fetch_refs
|
||||||
|
and info.status > TaskStatus.PREPARING
|
||||||
|
):
|
||||||
|
|
||||||
def on_diverged(_ref: str, _checkpoint: bool):
|
def on_diverged(_ref: str, _checkpoint: bool):
|
||||||
return False
|
return False
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ from typing import (
|
|||||||
Union,
|
Union,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
from scmrepo.exceptions import SCMError
|
||||||
|
|
||||||
from dvc.env import DVC_EXP_AUTO_PUSH, DVC_EXP_GIT_REMOTE
|
from dvc.env import DVC_EXP_AUTO_PUSH, DVC_EXP_GIT_REMOTE
|
||||||
from dvc.exceptions import DvcException
|
from dvc.exceptions import DvcException
|
||||||
from dvc.stage.serialize import to_lockfile
|
from dvc.stage.serialize import to_lockfile
|
||||||
@@ -361,21 +363,25 @@ class BaseExecutor(ABC):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
# fetch experiments
|
# fetch experiments
|
||||||
dest_scm.fetch_refspecs(
|
try:
|
||||||
self.git_url,
|
|
||||||
[f"{ref}:{ref}" for ref in refs],
|
|
||||||
on_diverged=on_diverged_ref,
|
|
||||||
force=force,
|
|
||||||
**kwargs,
|
|
||||||
)
|
|
||||||
# update last run checkpoint (if it exists)
|
|
||||||
if has_checkpoint:
|
|
||||||
dest_scm.fetch_refspecs(
|
dest_scm.fetch_refspecs(
|
||||||
self.git_url,
|
self.git_url,
|
||||||
[f"{EXEC_CHECKPOINT}:{EXEC_CHECKPOINT}"],
|
[f"{ref}:{ref}" for ref in refs],
|
||||||
force=True,
|
on_diverged=on_diverged_ref,
|
||||||
|
force=force,
|
||||||
**kwargs,
|
**kwargs,
|
||||||
)
|
)
|
||||||
|
# update last run checkpoint (if it exists)
|
||||||
|
if has_checkpoint:
|
||||||
|
dest_scm.fetch_refspecs(
|
||||||
|
self.git_url,
|
||||||
|
[f"{EXEC_CHECKPOINT}:{EXEC_CHECKPOINT}"],
|
||||||
|
force=True,
|
||||||
|
**kwargs,
|
||||||
|
)
|
||||||
|
except SCMError:
|
||||||
|
pass
|
||||||
|
|
||||||
return refs
|
return refs
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|||||||
+116
-34
@@ -5,7 +5,6 @@ from enum import Enum
|
|||||||
from itertools import chain
|
from itertools import chain
|
||||||
from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional, Union
|
from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional, Union
|
||||||
|
|
||||||
from dvc.repo.experiments.queue.base import QueueDoneResult
|
|
||||||
from dvc.repo.metrics.show import _gather_metrics
|
from dvc.repo.metrics.show import _gather_metrics
|
||||||
from dvc.repo.params.show import _gather_params
|
from dvc.repo.params.show import _gather_params
|
||||||
from dvc.scm import iter_revs
|
from dvc.scm import iter_revs
|
||||||
@@ -76,7 +75,7 @@ def _collect_experiment_commit(
|
|||||||
|
|
||||||
res["status"] = status.name
|
res["status"] = status.name
|
||||||
if status == ExpStatus.Running:
|
if status == ExpStatus.Running:
|
||||||
res["executor"] = running[exp_rev].get("location")
|
res["executor"] = running.get(exp_rev, {}).get("location", None)
|
||||||
else:
|
else:
|
||||||
res["executor"] = None
|
res["executor"] = None
|
||||||
|
|
||||||
@@ -180,6 +179,81 @@ def get_names(repo: "Repo", result: Dict[str, Dict[str, Any]]):
|
|||||||
|
|
||||||
|
|
||||||
# flake8: noqa: C901
|
# flake8: noqa: C901
|
||||||
|
def _collect_active_experiment(
|
||||||
|
repo: "Repo",
|
||||||
|
found_revs: Dict[str, List[str]],
|
||||||
|
running: Dict[str, Any],
|
||||||
|
**kwargs,
|
||||||
|
) -> Dict[str, Dict[str, Any]]:
|
||||||
|
result: Dict[str, Dict] = defaultdict(OrderedDict)
|
||||||
|
for entry in chain(
|
||||||
|
repo.experiments.tempdir_queue.iter_active(),
|
||||||
|
repo.experiments.celery_queue.iter_active(),
|
||||||
|
):
|
||||||
|
stash_rev = entry.stash_rev
|
||||||
|
if entry.baseline_rev in found_revs and (
|
||||||
|
stash_rev not in running or not running[stash_rev].get("last")
|
||||||
|
):
|
||||||
|
result[entry.baseline_rev][stash_rev] = _collect_experiment_commit(
|
||||||
|
repo,
|
||||||
|
stash_rev,
|
||||||
|
status=ExpStatus.Running,
|
||||||
|
running=running,
|
||||||
|
**kwargs,
|
||||||
|
)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def _collect_queued_experiment(
|
||||||
|
repo: "Repo",
|
||||||
|
found_revs: Dict[str, List[str]],
|
||||||
|
running: Dict[str, Any],
|
||||||
|
**kwargs,
|
||||||
|
) -> Dict[str, Dict[str, Any]]:
|
||||||
|
result: Dict[str, Dict] = defaultdict(OrderedDict)
|
||||||
|
for entry in repo.experiments.celery_queue.iter_queued():
|
||||||
|
stash_rev = entry.stash_rev
|
||||||
|
if entry.baseline_rev in found_revs:
|
||||||
|
result[entry.baseline_rev][stash_rev] = _collect_experiment_commit(
|
||||||
|
repo,
|
||||||
|
stash_rev,
|
||||||
|
status=ExpStatus.Queued,
|
||||||
|
running=running,
|
||||||
|
**kwargs,
|
||||||
|
)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def _collect_failed_experiment(
|
||||||
|
repo: "Repo",
|
||||||
|
found_revs: Dict[str, List[str]],
|
||||||
|
running: Dict[str, Any],
|
||||||
|
**kwargs,
|
||||||
|
) -> Dict[str, Dict[str, Any]]:
|
||||||
|
result: Dict[str, Dict] = defaultdict(OrderedDict)
|
||||||
|
for queue_done_result in repo.experiments.celery_queue.iter_failed():
|
||||||
|
entry = queue_done_result.entry
|
||||||
|
stash_rev = entry.stash_rev
|
||||||
|
if entry.baseline_rev in found_revs:
|
||||||
|
experiment = _collect_experiment_commit(
|
||||||
|
repo,
|
||||||
|
stash_rev,
|
||||||
|
status=ExpStatus.Failed,
|
||||||
|
running=running,
|
||||||
|
**kwargs,
|
||||||
|
)
|
||||||
|
result[entry.baseline_rev][stash_rev] = experiment
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def update_new(
|
||||||
|
to_dict: Dict[str, Dict[str, Any]], from_dict: Dict[str, Dict[str, Any]]
|
||||||
|
):
|
||||||
|
for baseline, experiments in from_dict.items():
|
||||||
|
for rev, experiment in experiments.items():
|
||||||
|
to_dict[baseline][rev] = to_dict[baseline].get(rev, experiment)
|
||||||
|
|
||||||
|
|
||||||
def show(
|
def show(
|
||||||
repo: "Repo",
|
repo: "Repo",
|
||||||
all_branches=False,
|
all_branches=False,
|
||||||
@@ -215,6 +289,39 @@ def show(
|
|||||||
|
|
||||||
running = repo.experiments.get_running_exps(fetch_refs=fetch_running)
|
running = repo.experiments.get_running_exps(fetch_refs=fetch_running)
|
||||||
|
|
||||||
|
queued_experiment = (
|
||||||
|
_collect_queued_experiment(
|
||||||
|
repo,
|
||||||
|
found_revs,
|
||||||
|
running,
|
||||||
|
param_deps=param_deps,
|
||||||
|
onerror=onerror,
|
||||||
|
)
|
||||||
|
if not hide_queued
|
||||||
|
else {}
|
||||||
|
)
|
||||||
|
|
||||||
|
active_experiment = _collect_active_experiment(
|
||||||
|
repo,
|
||||||
|
found_revs,
|
||||||
|
running,
|
||||||
|
param_deps=param_deps,
|
||||||
|
onerror=onerror,
|
||||||
|
)
|
||||||
|
|
||||||
|
failed_experiments = (
|
||||||
|
_collect_failed_experiment(
|
||||||
|
repo,
|
||||||
|
found_revs,
|
||||||
|
running,
|
||||||
|
sha_only=sha_only,
|
||||||
|
param_deps=param_deps,
|
||||||
|
onerror=onerror,
|
||||||
|
)
|
||||||
|
if not hide_failed
|
||||||
|
else {}
|
||||||
|
)
|
||||||
|
|
||||||
for rev in found_revs:
|
for rev in found_revs:
|
||||||
status = ExpStatus.Running if rev in running else ExpStatus.Success
|
status = ExpStatus.Running if rev in running else ExpStatus.Success
|
||||||
res[rev]["baseline"] = _collect_experiment_commit(
|
res[rev]["baseline"] = _collect_experiment_commit(
|
||||||
@@ -249,38 +356,13 @@ def show(
|
|||||||
onerror=onerror,
|
onerror=onerror,
|
||||||
)
|
)
|
||||||
|
|
||||||
# collect standalone & celery experiments
|
if not hide_failed:
|
||||||
for entry in chain(
|
update_new(res, failed_experiments)
|
||||||
repo.experiments.tempdir_queue.iter_active(),
|
|
||||||
repo.experiments.celery_queue.iter_active(),
|
update_new(res, active_experiment)
|
||||||
repo.experiments.celery_queue.iter_queued(),
|
|
||||||
repo.experiments.celery_queue.iter_failed(),
|
if not hide_queued:
|
||||||
):
|
update_new(res, queued_experiment)
|
||||||
if isinstance(entry, QueueDoneResult):
|
|
||||||
entry = entry.entry
|
|
||||||
if hide_failed:
|
|
||||||
continue
|
|
||||||
status = ExpStatus.Failed
|
|
||||||
elif entry.stash_rev in running:
|
|
||||||
status = ExpStatus.Running
|
|
||||||
else:
|
|
||||||
if hide_queued:
|
|
||||||
continue
|
|
||||||
status = ExpStatus.Queued
|
|
||||||
stash_rev = entry.stash_rev
|
|
||||||
if entry.baseline_rev in found_revs:
|
|
||||||
if stash_rev not in running or not running[stash_rev].get(
|
|
||||||
"last"
|
|
||||||
):
|
|
||||||
experiment = _collect_experiment_commit(
|
|
||||||
repo,
|
|
||||||
stash_rev,
|
|
||||||
status=status,
|
|
||||||
param_deps=param_deps,
|
|
||||||
running=running,
|
|
||||||
onerror=onerror,
|
|
||||||
)
|
|
||||||
res[entry.baseline_rev][stash_rev] = experiment
|
|
||||||
|
|
||||||
if not sha_only:
|
if not sha_only:
|
||||||
get_names(repo, res)
|
get_names(repo, res)
|
||||||
|
|||||||
@@ -163,6 +163,7 @@ def test_show_queued(tmp_dir, scm, dvc, exp_stage):
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.vscode
|
@pytest.mark.vscode
|
||||||
|
@pytest.mark.xfail(strict=False, reason="pytest-celery flaky")
|
||||||
def test_show_failed_experiment(tmp_dir, scm, dvc, failed_exp_stage):
|
def test_show_failed_experiment(tmp_dir, scm, dvc, failed_exp_stage):
|
||||||
baseline_rev = scm.get_rev()
|
baseline_rev = scm.get_rev()
|
||||||
timestamp = datetime.fromtimestamp(
|
timestamp = datetime.fromtimestamp(
|
||||||
@@ -423,8 +424,6 @@ def test_show_running_workspace(tmp_dir, scm, dvc, exp_stage, capsys, status):
|
|||||||
makedirs(os.path.dirname(pidfile), True)
|
makedirs(os.path.dirname(pidfile), True)
|
||||||
(tmp_dir / pidfile).dump_json(info.asdict())
|
(tmp_dir / pidfile).dump_json(info.asdict())
|
||||||
|
|
||||||
print(dvc.experiments.show().get("workspace"))
|
|
||||||
|
|
||||||
assert dvc.experiments.show().get("workspace") == {
|
assert dvc.experiments.show().get("workspace") == {
|
||||||
"baseline": {
|
"baseline": {
|
||||||
"data": {
|
"data": {
|
||||||
@@ -558,6 +557,7 @@ def test_show_running_checkpoint(tmp_dir, scm, dvc, checkpoint_stage, mocker):
|
|||||||
git_url="foo.git",
|
git_url="foo.git",
|
||||||
baseline_rev=baseline_rev,
|
baseline_rev=baseline_rev,
|
||||||
location=TempDirExecutor.DEFAULT_LOCATION,
|
location=TempDirExecutor.DEFAULT_LOCATION,
|
||||||
|
status=TaskStatus.RUNNING,
|
||||||
)
|
)
|
||||||
makedirs(os.path.dirname(pidfile), True)
|
makedirs(os.path.dirname(pidfile), True)
|
||||||
(tmp_dir / pidfile).dump_json(info.asdict())
|
(tmp_dir / pidfile).dump_json(info.asdict())
|
||||||
|
|||||||
Reference in New Issue
Block a user