Skip to content

Commit 5d3c405

Browse files
authored
director: renew cache in the background instead of clearing cache (#1496)
* renew cache in the background instead of clearing cache * add 10% sleep time in test_registry
1 parent 0843954 commit 5d3c405

File tree

5 files changed

+217
-100
lines changed

5 files changed

+217
-100
lines changed

services/director/src/simcore_service_director/api/v0/schemas/project-v0.0.1.json

+21-7
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@
4141
},
4242
"prjOwner": {
4343
"type": "string",
44-
"description": "user uuid"
44+
"format": "idn-email",
45+
"description": "user email"
4546
},
4647
"accessRights": {
4748
"type": "object",
@@ -106,7 +107,7 @@
106107
"type": "string"
107108
},
108109
"progress": {
109-
"type":"number",
110+
"type": "number",
110111
"maximum": 100,
111112
"minimum": 0,
112113
"description": "the node progress value"
@@ -158,7 +159,10 @@
158159
],
159160
"properties": {
160161
"store": {
161-
"type": ["string", "integer"]
162+
"type": [
163+
"string",
164+
"integer"
165+
]
162166
},
163167
"dataset": {
164168
"type": "string"
@@ -181,7 +185,11 @@
181185
"patternProperties": {
182186
"^[-_a-zA-Z0-9]+$": {
183187
"type": "string",
184-
"enum": ["Invisible", "ReadOnly", "ReadAndWrite"],
188+
"enum": [
189+
"Invisible",
190+
"ReadOnly",
191+
"ReadAndWrite"
192+
],
185193
"default": "ReadAndWrite",
186194
"examples": [
187195
"ReadOnly"
@@ -224,7 +232,10 @@
224232
],
225233
"properties": {
226234
"store": {
227-
"type": ["string", "integer"]
235+
"type": [
236+
"string",
237+
"integer"
238+
]
228239
},
229240
"dataset": {
230241
"type": "string"
@@ -258,7 +269,10 @@
258269
]
259270
},
260271
"parent": {
261-
"type": ["string", "null"],
272+
"type": [
273+
"string",
274+
"null"
275+
],
262276
"pattern": "^\\S+$",
263277
"description": "Parent's (group-nodes') node ID s.",
264278
"examples": [
@@ -293,4 +307,4 @@
293307
}
294308
}
295309
}
296-
}
310+
}
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,32 @@
11
from functools import wraps
2-
from typing import Callable, Dict, Tuple
2+
from typing import Coroutine, Dict, Tuple
33

44
from aiohttp import web
5+
56
from simcore_service_director import config
6-
from yarl import URL
77

88

9-
def cache_requests(http_request: Callable):
10-
@wraps(http_request)
11-
async def wrapped(app: web.Application, url: URL, method: str ="GET") -> Tuple[Dict, Dict]:
9+
def cache_requests(func: Coroutine, no_cache: bool = False):
10+
@wraps(func)
11+
async def wrapped(
12+
app: web.Application, url: str, method: str, *args, **kwargs
13+
) -> Tuple[Dict, Dict]:
1214
is_cache_enabled = config.DIRECTOR_REGISTRY_CACHING and method == "GET"
13-
if is_cache_enabled:
15+
cache_key = f"{url}:{method}"
16+
if is_cache_enabled and not no_cache:
1417
cache_data = app[config.APP_REGISTRY_CACHE_DATA_KEY]
15-
cache_key = "{}_{}".format(url, method)
1618
if cache_key in cache_data:
1719
return cache_data[cache_key]
1820

19-
resp_data, resp_headers = await http_request(app, url, method)
21+
resp_data, resp_headers = await func(app, url, method, *args, **kwargs)
2022

2123
if is_cache_enabled:
24+
cache_data = app[config.APP_REGISTRY_CACHE_DATA_KEY]
2225
cache_data[cache_key] = (resp_data, resp_headers)
2326

2427
return (resp_data, resp_headers)
2528

2629
return wrapped
2730

28-
__all__ = [
29-
"cache_requests"
30-
]
31+
32+
__all__ = ["cache_requests"]

services/director/src/simcore_service_director/registry_cache_task.py

+35-13
Original file line numberDiff line numberDiff line change
@@ -5,35 +5,60 @@
55

66
from simcore_service_director import config, exceptions, registry_proxy
77
from simcore_service_director.config import APP_REGISTRY_CACHE_DATA_KEY
8+
from servicelib.utils import logged_gather
89

910
_logger = logging.getLogger(__name__)
1011

1112
TASK_NAME: str = __name__ + "_registry_caching_task"
13+
14+
1215
async def registry_caching_task(app: web.Application) -> None:
1316
try:
14-
_logger.info("%s: initializing...", TASK_NAME)
17+
_logger.info("%s: initializing cache...", TASK_NAME)
1518
app[APP_REGISTRY_CACHE_DATA_KEY].clear()
19+
await registry_proxy.list_services(app, registry_proxy.ServiceType.ALL)
1620
_logger.info("%s: initialisation completed", TASK_NAME)
1721
while True:
18-
_logger.info("%s: waking up, cleaning registry cache...", TASK_NAME)
19-
app[APP_REGISTRY_CACHE_DATA_KEY].clear()
20-
_logger.info("%s: caching services list...", TASK_NAME)
22+
_logger.info("%s: waking up, refreshing cache...", TASK_NAME)
2123
try:
22-
await registry_proxy.list_services(app, registry_proxy.ServiceType.ALL)
24+
keys = []
25+
refresh_tasks = []
26+
for key in app[APP_REGISTRY_CACHE_DATA_KEY]:
27+
path, method = key.split(":")
28+
_logger.debug("refresh %s:%s", method, path)
29+
refresh_tasks.append(
30+
registry_proxy.registry_request(
31+
app, path, method, no_cache=True
32+
)
33+
)
34+
keys = list(app[APP_REGISTRY_CACHE_DATA_KEY].keys())
35+
results = await logged_gather(*refresh_tasks)
36+
37+
for key, result in zip(keys, results):
38+
app[APP_REGISTRY_CACHE_DATA_KEY][key] = result
39+
2340
except exceptions.DirectorException:
2441
# if the registry is temporarily not available this might happen
42+
_logger.exception(
43+
"%s: exception while refreshing cache, clean cache...", TASK_NAME
44+
)
2545
app[APP_REGISTRY_CACHE_DATA_KEY].clear()
2646

27-
_logger.info("%s: sleeping for %ss...", TASK_NAME, config.DIRECTOR_REGISTRY_CACHING_TTL)
47+
_logger.info(
48+
"cache refreshed %s: sleeping for %ss...",
49+
TASK_NAME,
50+
config.DIRECTOR_REGISTRY_CACHING_TTL,
51+
)
2852
await asyncio.sleep(config.DIRECTOR_REGISTRY_CACHING_TTL)
2953
except asyncio.CancelledError:
3054
_logger.info("%s: cancelling task...", TASK_NAME)
31-
except Exception: #pylint: disable=broad-except
32-
_logger.exception("%s: exception while retrieving list of services in cache", TASK_NAME)
55+
except Exception: # pylint: disable=broad-except
56+
_logger.exception("%s: Unhandled exception while refreshing cache", TASK_NAME)
3357
finally:
3458
_logger.info("%s: finished task...clearing cache...", TASK_NAME)
3559
app[APP_REGISTRY_CACHE_DATA_KEY].clear()
3660

61+
3762
async def setup_registry_caching_task(app: web.Application) -> None:
3863
app[APP_REGISTRY_CACHE_DATA_KEY] = {}
3964
app[TASK_NAME] = asyncio.get_event_loop().create_task(registry_caching_task(app))
@@ -44,13 +69,10 @@ async def setup_registry_caching_task(app: web.Application) -> None:
4469
task.cancel()
4570
await task
4671

72+
4773
def setup(app: web.Application) -> None:
4874
if config.DIRECTOR_REGISTRY_CACHING:
4975
app.cleanup_ctx.append(setup_registry_caching_task)
50-
5176

5277

53-
__all__ = [
54-
"setup",
55-
"APP_REGISTRY_CACHE_DATA_KEY"
56-
]
78+
__all__ = ["setup", "APP_REGISTRY_CACHE_DATA_KEY"]

0 commit comments

Comments
 (0)