2
2
3
3
import functools
4
4
import logging
5
+ import threading
5
6
6
7
log = logging .getLogger (__name__ )
7
8
@@ -15,6 +16,7 @@ def __init__(self):
15
16
self .exception = None
16
17
self ._callbacks = []
17
18
self ._errbacks = []
19
+ self ._lock = threading .Lock ()
18
20
19
21
def succeeded (self ):
20
22
return self .is_done and not bool (self .exception )
@@ -30,37 +32,46 @@ def retriable(self):
30
32
31
33
def success (self , value ):
32
34
assert not self .is_done , 'Future is already complete'
33
- self .value = value
34
- self .is_done = True
35
+ with self ._lock :
36
+ self .value = value
37
+ self .is_done = True
35
38
if self ._callbacks :
36
39
self ._call_backs ('callback' , self ._callbacks , self .value )
37
40
return self
38
41
39
42
def failure (self , e ):
40
43
assert not self .is_done , 'Future is already complete'
41
- self . exception = e if type (e ) is not type else e ()
42
- assert isinstance (self . exception , BaseException ), (
44
+ exception = e if type (e ) is not type else e ()
45
+ assert isinstance (exception , BaseException ), (
43
46
'future failed without an exception' )
44
- self .is_done = True
47
+ with self ._lock :
48
+ self .exception = exception
49
+ self .is_done = True
45
50
self ._call_backs ('errback' , self ._errbacks , self .exception )
46
51
return self
47
52
48
53
def add_callback (self , f , * args , ** kwargs ):
49
54
if args or kwargs :
50
55
f = functools .partial (f , * args , ** kwargs )
51
- if self .is_done and not self .exception :
52
- self ._call_backs ('callback' , [f ], self .value )
53
- else :
54
- self ._callbacks .append (f )
56
+ with self ._lock :
57
+ if not self .is_done :
58
+ self ._callbacks .append (f )
59
+ elif self .succeeded ():
60
+ self ._lock .release ()
61
+ self ._call_backs ('callback' , [f ], self .value )
62
+ self ._lock .acquire ()
55
63
return self
56
64
57
65
def add_errback (self , f , * args , ** kwargs ):
58
66
if args or kwargs :
59
67
f = functools .partial (f , * args , ** kwargs )
60
- if self .is_done and self .exception :
61
- self ._call_backs ('errback' , [f ], self .exception )
62
- else :
63
- self ._errbacks .append (f )
68
+ with self ._lock :
69
+ if not self .is_done :
70
+ self ._errbacks .append (f )
71
+ elif self .failed ():
72
+ self ._lock .release ()
73
+ self ._call_backs ('errback' , [f ], self .exception )
74
+ self ._lock .acquire ()
64
75
return self
65
76
66
77
def add_both (self , f , * args , ** kwargs ):
0 commit comments