13
13
# See the License for the specific language governing permissions and
14
14
# limitations under the License.
15
15
import logging
16
+ from typing import TYPE_CHECKING , Any , Callable , Dict , Generic , Optional , TypeVar
16
17
17
18
from twisted .internet import defer
18
19
19
20
from synapse .logging .context import make_deferred_yieldable , run_in_background
20
21
from synapse .util .async_helpers import ObservableDeferred
21
22
from synapse .util .caches import register_cache
22
23
24
+ if TYPE_CHECKING :
25
+ from synapse .app .homeserver import HomeServer
26
+
23
27
logger = logging .getLogger (__name__ )
24
28
29
+ T = TypeVar ("T" )
30
+
25
31
26
- class ResponseCache :
32
+ class ResponseCache ( Generic [ T ]) :
27
33
"""
28
34
This caches a deferred response. Until the deferred completes it will be
29
35
returned from the cache. This means that if the client retries the request
30
36
while the response is still being computed, that original response will be
31
37
used rather than trying to compute a new response.
32
38
"""
33
39
34
- def __init__ (self , hs , name , timeout_ms = 0 ):
35
- self .pending_result_cache = {} # Requests that haven't finished yet.
40
+ def __init__ (self , hs : "HomeServer" , name : str , timeout_ms : float = 0 ):
41
+ # Requests that haven't finished yet.
42
+ self .pending_result_cache = {} # type: Dict[T, ObservableDeferred]
36
43
37
44
self .clock = hs .get_clock ()
38
45
self .timeout_sec = timeout_ms / 1000.0
39
46
40
47
self ._name = name
41
48
self ._metrics = register_cache ("response_cache" , name , self , resizable = False )
42
49
43
- def size (self ):
50
+ def size (self ) -> int :
44
51
return len (self .pending_result_cache )
45
52
46
- def __len__ (self ):
53
+ def __len__ (self ) -> int :
47
54
return self .size ()
48
55
49
- def get (self , key ) :
56
+ def get (self , key : T ) -> Optional [ defer . Deferred ] :
50
57
"""Look up the given key.
51
58
52
59
Can return either a new Deferred (which also doesn't follow the synapse
@@ -58,12 +65,11 @@ def get(self, key):
58
65
from an absent cache entry.
59
66
60
67
Args:
61
- key (hashable):
68
+ key: key to get/set in the cache
62
69
63
70
Returns:
64
- twisted.internet.defer.Deferred|None|E: None if there is no entry
65
- for this key; otherwise either a deferred result or the result
66
- itself.
71
+ None if there is no entry for this key; otherwise a deferred which
72
+ resolves to the result.
67
73
"""
68
74
result = self .pending_result_cache .get (key )
69
75
if result is not None :
@@ -73,7 +79,7 @@ def get(self, key):
73
79
self ._metrics .inc_misses ()
74
80
return None
75
81
76
- def set (self , key , deferred ) :
82
+ def set (self , key : T , deferred : defer . Deferred ) -> defer . Deferred :
77
83
"""Set the entry for the given key to the given deferred.
78
84
79
85
*deferred* should run its callbacks in the sentinel logcontext (ie,
@@ -85,12 +91,11 @@ def set(self, key, deferred):
85
91
result. You will probably want to make_deferred_yieldable the result.
86
92
87
93
Args:
88
- key (hashable):
89
- deferred (twisted.internet.defer.Deferred[T):
94
+ key: key to get/set in the cache
95
+ deferred: The deferred which resolves to the result.
90
96
91
97
Returns:
92
- twisted.internet.defer.Deferred[T]|T: a new deferred, or the actual
93
- result.
98
+ A new deferred which resolves to the actual result.
94
99
"""
95
100
result = ObservableDeferred (deferred , consumeErrors = True )
96
101
self .pending_result_cache [key ] = result
@@ -107,7 +112,9 @@ def remove(r):
107
112
result .addBoth (remove )
108
113
return result .observe ()
109
114
110
- def wrap (self , key , callback , * args , ** kwargs ):
115
+ def wrap (
116
+ self , key : T , callback : "Callable[..., Any]" , * args : Any , ** kwargs : Any
117
+ ) -> defer .Deferred :
111
118
"""Wrap together a *get* and *set* call, taking care of logcontexts
112
119
113
120
First looks up the key in the cache, and if it is present makes it
@@ -118,29 +125,28 @@ def wrap(self, key, callback, *args, **kwargs):
118
125
119
126
Example usage:
120
127
121
- @defer.inlineCallbacks
122
- def handle_request(request):
128
+ async def handle_request(request):
123
129
# etc
124
130
return result
125
131
126
- result = yield response_cache.wrap(
132
+ result = await response_cache.wrap(
127
133
key,
128
134
handle_request,
129
135
request,
130
136
)
131
137
132
138
Args:
133
- key (hashable) : key to get/set in the cache
139
+ key: key to get/set in the cache
134
140
135
- callback (callable) : function to call if the key is not found in
141
+ callback: function to call if the key is not found in
136
142
the cache
137
143
138
144
*args: positional parameters to pass to the callback, if it is used
139
145
140
146
**kwargs: named parameters to pass to the callback, if it is used
141
147
142
148
Returns:
143
- twisted.internet.defer. Deferred: yieldable result
149
+ Deferred which resolves to the result
144
150
"""
145
151
result = self .get (key )
146
152
if not result :
0 commit comments