@@ -274,6 +274,36 @@ def long_post(*args, **kwargs):
274274 assert metrics_file .read_text () == metrics_content
275275
276276
277+ def test_studio_update_raises_exception (tmp_path , mocked_dvc_repo , mocked_studio_post ):
278+ # Test that if a studio update raises an exception, main process doesn't hang on
279+ # queue join in the Live main thread.
280+ # https://github.com/iterative/dvclive/pull/864
281+ mocked_post , valid_response = mocked_studio_post
282+
283+ def post_raises_exception (* args , ** kwargs ):
284+ if kwargs ["json" ]["type" ] == "data" :
285+ # We'll hit this sleep only once, other calls are ignored
286+ # after the exception is raised
287+ time .sleep (1 )
288+ raise Exception ("test exception" ) # noqa: TRY002, TRY003
289+ return valid_response
290+
291+ mocked_post .side_effect = post_raises_exception
292+
293+ with Live () as live :
294+ live .log_metric ("foo" , 1 )
295+ live .log_metric ("foo" , 2 )
296+ live .log_metric ("foo" , 3 )
297+
298+ # Only 1 data call is made, other calls are ignored after the exception is raised
299+ assert mocked_post .call_count == 3
300+ assert [e .kwargs ["json" ]["type" ] for e in mocked_post .call_args_list ] == [
301+ "start" ,
302+ "data" ,
303+ "done" ,
304+ ]
305+
306+
277307@pytest .mark .studio
278308def test_post_to_studio_skip_start_and_done_on_env_var (
279309 tmp_dir , mocked_dvc_repo , mocked_studio_post , monkeypatch
0 commit comments