Skip to content

Commit 8213721

Browse files
author
Prince Kumar
committed
[Observability] Log interrupted processing tasks on unexpected worker death
Fixes #9263
1 parent a36b8ec commit 8213721

2 files changed

Lines changed: 135 additions & 133 deletions

File tree

distributed/tests/test_scheduler.py

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5216,3 +5216,138 @@ def __dask_postcompute__(self):
52165216
sum([s.is_rootish(v) and v.run_spec.data_producer for v in s.tasks.values()])
52175217
== 2
52185218
)
5219+
5220+
5221+
@gen_cluster(client=True)
5222+
async def test_log_remove_worker(c, s, a, b):
5223+
# Computed task
5224+
x = c.submit(inc, 1, key="x", workers=a.address)
5225+
await x
5226+
ev = Event()
5227+
# Processing task
5228+
y = c.submit(
5229+
lambda ev: ev.wait(), ev, key="y", workers=a.address, allow_other_workers=True
5230+
)
5231+
await wait_for_state("y", "processing", s)
5232+
# Scattered task
5233+
z = await c.scatter({"z": 3}, workers=a.address)
5234+
5235+
s._broker.truncate()
5236+
5237+
with captured_logger("distributed.scheduler", level=logging.INFO) as log:
5238+
# Successful graceful shutdown
5239+
await s.retire_workers([a.address], stimulus_id="graceful")
5240+
# Refuse to retire gracefully as there's nowhere to put x and z
5241+
await s.retire_workers([b.address], stimulus_id="graceful_abort")
5242+
await asyncio.sleep(0.2)
5243+
# Ungraceful shutdown
5244+
await s.remove_worker(b.address, stimulus_id="ungraceful")
5245+
await asyncio.sleep(0.2)
5246+
await ev.set()
5247+
5248+
assert log.getvalue().splitlines() == [
5249+
# Successful graceful
5250+
f"Retire worker addresses (stimulus_id='graceful') ['{a.address}']",
5251+
f"Remove worker addr: {a.address} name: {a.name} (stimulus_id='graceful')",
5252+
f"Retired worker '{a.address}' (stimulus_id='graceful')",
5253+
# Aborted graceful
5254+
f"Retire worker addresses (stimulus_id='graceful_abort') ['{b.address}']",
5255+
f"Could not retire worker '{b.address}': unique data could not be "
5256+
"moved to any other worker (stimulus_id='graceful_abort')",
5257+
# Ungraceful
5258+
f"Remove worker addr: {b.address} name: {b.name} (stimulus_id='ungraceful')",
5259+
f"Removing worker '{b.address}' caused the cluster to lose already "
5260+
"computed task(s), which will be recomputed elsewhere: {'x'} "
5261+
"(stimulus_id='ungraceful')",
5262+
f"Removing worker '{b.address}' caused the cluster to lose scattered "
5263+
"data, which can't be recovered: {'z'} (stimulus_id='ungraceful')",
5264+
f"Worker {b.address!r} dropped unexpectedly. Interrupting 1 "
5265+
"processing tasks: {'y'} (stimulus_id='ungraceful')",
5266+
"Lost all workers",
5267+
]
5268+
5269+
events = {topic: [ev for _, ev in evs] for topic, evs in s.get_events().items()}
5270+
for evs in events.values():
5271+
for ev in evs:
5272+
if ev.get("action", None) == "retire-workers":
5273+
for k in ("retired", "could-not-retire"):
5274+
ev[k] = {addr: "snip" for addr in ev[k]}
5275+
if "stimulus_id" in ev: # Strip timestamp
5276+
ev["stimulus_id"] = ev["stimulus_id"].rsplit("-", 1)[0]
5277+
5278+
assert events == {
5279+
a.address: [
5280+
{
5281+
"action": "worker-status-change",
5282+
"prev-status": "running",
5283+
"status": "closing_gracefully",
5284+
"stimulus_id": "graceful",
5285+
},
5286+
{
5287+
"action": "remove-worker",
5288+
"lost-computed-tasks": set(),
5289+
"lost-scattered-tasks": set(),
5290+
"processing-tasks": {"y"},
5291+
"expected": True,
5292+
"stimulus_id": "graceful",
5293+
},
5294+
{"action": "retired", "stimulus_id": "graceful"},
5295+
],
5296+
b.address: [
5297+
{
5298+
"action": "worker-status-change",
5299+
"prev-status": "running",
5300+
"status": "closing_gracefully",
5301+
"stimulus_id": "graceful_abort",
5302+
},
5303+
{"action": "could-not-retire", "stimulus_id": "graceful_abort"},
5304+
{
5305+
"action": "worker-status-change",
5306+
"prev-status": "closing_gracefully",
5307+
"status": "running",
5308+
"stimulus_id": "worker-status-change",
5309+
},
5310+
{
5311+
"action": "remove-worker",
5312+
"lost-computed-tasks": {"x"},
5313+
"lost-scattered-tasks": {"z"},
5314+
"processing-tasks": {"y"},
5315+
"expected": False,
5316+
"stimulus_id": "ungraceful",
5317+
},
5318+
{"action": "closing-worker", "reason": "scheduler-remove-worker"},
5319+
],
5320+
"all": [
5321+
{
5322+
"action": "remove-worker",
5323+
"lost-computed-tasks": set(),
5324+
"lost-scattered-tasks": set(),
5325+
"processing-tasks": {"y"},
5326+
"expected": True,
5327+
"stimulus_id": "graceful",
5328+
"worker": a.address,
5329+
},
5330+
{
5331+
"action": "retire-workers",
5332+
"stimulus_id": "graceful",
5333+
"retired": {a.address: "snip"},
5334+
"could-not-retire": {},
5335+
},
5336+
{
5337+
"action": "retire-workers",
5338+
"stimulus_id": "graceful_abort",
5339+
"retired": {},
5340+
"could-not-retire": {b.address: "snip"},
5341+
},
5342+
{
5343+
"action": "remove-worker",
5344+
"lost-computed-tasks": {"x"},
5345+
"lost-scattered-tasks": {"z"},
5346+
"processing-tasks": {"y"},
5347+
"expected": False,
5348+
"stimulus_id": "ungraceful",
5349+
"worker": b.address,
5350+
},
5351+
],
5352+
"worker-get-client": [{"client": c.id, "timeout": 5, "worker": b.address}],
5353+
}

distributed/tests/test_worker.py

Lines changed: 0 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -2965,139 +2965,6 @@ async def test_worker_status_sync(s, a):
29652965
]
29662966

29672967

2968-
@gen_cluster(client=True)
2969-
async def test_log_remove_worker(c, s, a, b):
2970-
# Computed task
2971-
x = c.submit(inc, 1, key="x", workers=a.address)
2972-
await x
2973-
ev = Event()
2974-
# Processing task
2975-
y = c.submit(
2976-
lambda ev: ev.wait(), ev, key="y", workers=a.address, allow_other_workers=True
2977-
)
2978-
await wait_for_state("y", "processing", s)
2979-
# Scattered task
2980-
z = await c.scatter({"z": 3}, workers=a.address)
2981-
2982-
s._broker.truncate()
2983-
2984-
with captured_logger("distributed.scheduler", level=logging.INFO) as log:
2985-
# Successful graceful shutdown
2986-
await s.retire_workers([a.address], stimulus_id="graceful")
2987-
# Refuse to retire gracefully as there's nowhere to put x and z
2988-
await s.retire_workers([b.address], stimulus_id="graceful_abort")
2989-
await asyncio.sleep(0.2)
2990-
# Ungraceful shutdown
2991-
await s.remove_worker(b.address, stimulus_id="ungraceful")
2992-
await asyncio.sleep(0.2)
2993-
await ev.set()
2994-
2995-
assert log.getvalue().splitlines() == [
2996-
# Successful graceful
2997-
f"Retire worker addresses (stimulus_id='graceful') ['{a.address}']",
2998-
f"Remove worker addr: {a.address} name: {a.name} (stimulus_id='graceful')",
2999-
f"Retired worker '{a.address}' (stimulus_id='graceful')",
3000-
# Aborted graceful
3001-
f"Retire worker addresses (stimulus_id='graceful_abort') ['{b.address}']",
3002-
f"Could not retire worker '{b.address}': unique data could not be "
3003-
"moved to any other worker (stimulus_id='graceful_abort')",
3004-
# Ungraceful
3005-
f"Remove worker addr: {b.address} name: {b.name} (stimulus_id='ungraceful')",
3006-
f"Removing worker '{b.address}' caused the cluster to lose already "
3007-
"computed task(s), which will be recomputed elsewhere: {'x'} "
3008-
"(stimulus_id='ungraceful')",
3009-
f"Removing worker '{b.address}' caused the cluster to lose scattered "
3010-
"data, which can't be recovered: {'z'} (stimulus_id='ungraceful')",
3011-
"Lost all workers",
3012-
]
3013-
3014-
events = {topic: [ev for _, ev in evs] for topic, evs in s.get_events().items()}
3015-
for evs in events.values():
3016-
for ev in evs:
3017-
if ev.get("action", None) == "retire-workers":
3018-
for k in ("retired", "could-not-retire"):
3019-
ev[k] = {addr: "snip" for addr in ev[k]}
3020-
if "stimulus_id" in ev: # Strip timestamp
3021-
ev["stimulus_id"] = ev["stimulus_id"].rsplit("-", 1)[0]
3022-
3023-
assert events == {
3024-
a.address: [
3025-
{
3026-
"action": "worker-status-change",
3027-
"prev-status": "running",
3028-
"status": "closing_gracefully",
3029-
"stimulus_id": "graceful",
3030-
},
3031-
{
3032-
"action": "remove-worker",
3033-
"lost-computed-tasks": set(),
3034-
"lost-scattered-tasks": set(),
3035-
"processing-tasks": {"y"},
3036-
"expected": True,
3037-
"stimulus_id": "graceful",
3038-
},
3039-
{"action": "retired", "stimulus_id": "graceful"},
3040-
],
3041-
b.address: [
3042-
{
3043-
"action": "worker-status-change",
3044-
"prev-status": "running",
3045-
"status": "closing_gracefully",
3046-
"stimulus_id": "graceful_abort",
3047-
},
3048-
{"action": "could-not-retire", "stimulus_id": "graceful_abort"},
3049-
{
3050-
"action": "worker-status-change",
3051-
"prev-status": "closing_gracefully",
3052-
"status": "running",
3053-
"stimulus_id": "worker-status-change",
3054-
},
3055-
{
3056-
"action": "remove-worker",
3057-
"lost-computed-tasks": {"x"},
3058-
"lost-scattered-tasks": {"z"},
3059-
"processing-tasks": {"y"},
3060-
"expected": False,
3061-
"stimulus_id": "ungraceful",
3062-
},
3063-
{"action": "closing-worker", "reason": "scheduler-remove-worker"},
3064-
],
3065-
"all": [
3066-
{
3067-
"action": "remove-worker",
3068-
"lost-computed-tasks": set(),
3069-
"lost-scattered-tasks": set(),
3070-
"processing-tasks": {"y"},
3071-
"expected": True,
3072-
"stimulus_id": "graceful",
3073-
"worker": a.address,
3074-
},
3075-
{
3076-
"action": "retire-workers",
3077-
"stimulus_id": "graceful",
3078-
"retired": {a.address: "snip"},
3079-
"could-not-retire": {},
3080-
},
3081-
{
3082-
"action": "retire-workers",
3083-
"stimulus_id": "graceful_abort",
3084-
"retired": {},
3085-
"could-not-retire": {b.address: "snip"},
3086-
},
3087-
{
3088-
"action": "remove-worker",
3089-
"lost-computed-tasks": {"x"},
3090-
"lost-scattered-tasks": {"z"},
3091-
"processing-tasks": {"y"},
3092-
"expected": False,
3093-
"stimulus_id": "ungraceful",
3094-
"worker": b.address,
3095-
},
3096-
],
3097-
"worker-get-client": [{"client": c.id, "timeout": 5, "worker": b.address}],
3098-
}
3099-
3100-
31012968
@gen_cluster(client=True)
31022969
async def test_task_flight_compute_oserror(c, s, a, b):
31032970
"""If the remote worker dies while a task is in flight, the task may be

0 commit comments

Comments
 (0)