Skip to content

Commit 8a1ecb8

Browse files
authored
ensure tokens on futures are unique (#8569)
1 parent 137ff3e commit 8a1ecb8

2 files changed

Lines changed: 25 additions & 20 deletions

File tree

distributed/client.py

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import atexit
55
import copy
66
import inspect
7+
import itertools
78
import json
89
import logging
910
import os
@@ -31,7 +32,7 @@
3132
from tlz import first, groupby, merge, partition_all, valmap
3233

3334
import dask
34-
from dask.base import collections_to_dsk, normalize_token, tokenize
35+
from dask.base import collections_to_dsk, tokenize
3536
from dask.core import flatten, validate_key
3637
from dask.highlevelgraph import HighLevelGraph
3738
from dask.optimization import SubgraphCallable
@@ -210,11 +211,15 @@ class Future(WrappedKey):
210211

211212
_cb_executor = None
212213
_cb_executor_pid = None
214+
_counter = itertools.count()
215+
# Make sure this stays unique even across multiple processes or hosts
216+
_uid = uuid.uuid4().hex
213217

214-
def __init__(self, key, client=None, inform=True, state=None):
218+
def __init__(self, key, client=None, inform=True, state=None, _id=None):
215219
self.key = key
216220
self._cleared = False
217221
self._client = client
222+
self._id = _id or (Future._uid, next(Future._counter))
218223
self._input_state = state
219224
self._inform = inform
220225
self._state = None
@@ -499,8 +504,16 @@ def release(self):
499504
except TypeError: # pragma: no cover
500505
pass # Shutting down, add_callback may be None
501506

507+
@staticmethod
508+
def make_future(key, id):
509+
# Can't use kwargs in pickle __reduce__ methods
510+
return Future(key=key, _id=id)
511+
502512
def __reduce__(self) -> str | tuple[Any, ...]:
503-
return Future, (self.key,)
513+
return Future.make_future, (self.key, self._id)
514+
515+
def __dask_tokenize__(self):
516+
return (type(self).__name__, self.key, self._id)
504517

505518
def __del__(self):
506519
try:
@@ -643,18 +656,6 @@ async def done_callback(future, callback):
643656
callback(future)
644657

645658

646-
@partial(normalize_token.register, Future)
647-
def normalize_future(f):
648-
"""Returns the key and the type as a list
649-
650-
Parameters
651-
----------
652-
list
653-
The key and the type
654-
"""
655-
return [f.key, type(f)]
656-
657-
658659
class AllExit(Exception):
659660
"""Custom exception class to exit All(...) early."""
660661

@@ -3434,9 +3435,11 @@ def compute(
34343435

34353436
if traverse:
34363437
collections = tuple(
3437-
dask.delayed(a)
3438-
if isinstance(a, (list, set, tuple, dict, Iterator))
3439-
else a
3438+
(
3439+
dask.delayed(a)
3440+
if isinstance(a, (list, set, tuple, dict, Iterator))
3441+
else a
3442+
)
34403443
for a in collections
34413444
)
34423445

distributed/tests/test_client.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -863,11 +863,13 @@ async def test_tokenize_on_futures(c, s, a, b):
863863
y = c.submit(inc, 1)
864864
tok = tokenize(x)
865865
assert tokenize(x) == tokenize(x)
866-
assert tokenize(x) == tokenize(y)
866+
# Tokens must be unique per instance
867+
# See https://github.com/dask/distributed/issues/8561
868+
assert tokenize(x) != tokenize(y)
867869

868870
c.futures[x.key].finish()
869871

870-
assert tok == tokenize(y)
872+
assert tok != tokenize(y)
871873

872874

873875
@pytest.mark.skipif(not LINUX, reason="Need 127.0.0.2 to mean localhost")

0 commit comments

Comments
 (0)