Skip to content

Commit 993d4b7

Browse files
authored
🐛 Pass resource limits to dynamic services (ITISFoundation#3294)
* Extend environment section in docker compose spec
1 parent 9ce95f4 commit 993d4b7

File tree

2 files changed

+44
-3
lines changed

2 files changed

+44
-3
lines changed

services/director-v2/src/simcore_service_director_v2/modules/dynamic_sidecar/docker_compose_specs.py

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
)
1313
from servicelib.docker_compose import replace_env_vars_in_compose_spec
1414
from servicelib.json_serialization import json_dumps
15+
from servicelib.resources import CPU_RESOURCE_LIMIT_KEY, MEM_RESOURCE_LIMIT_KEY
1516
from settings_library.docker_registry import RegistrySettings
1617

1718
EnvKeyEqValueList = list[str]
@@ -107,14 +108,17 @@ def _update_resource_limits_and_reservations(
107108
) -> None:
108109
# example: '2.3' -> 2 ; '3.7' -> 3
109110
docker_compose_major_version: int = int(service_spec["version"].split(".")[0])
110-
111111
for spec_service_key, spec in service_spec["services"].items():
112112
resources: ResourcesDict = service_resources[spec_service_key].resources
113113
logger.debug("Resources for %s: %s", spec_service_key, f"{resources=}")
114114

115115
cpu: ResourceValue = resources["CPU"]
116116
memory: ResourceValue = resources["RAM"]
117117

118+
nano_cpu_limits: float = 0.0
119+
mem_limits: str = "0"
120+
_NANO = 10**9 # cpu's in nano-cpu's
121+
118122
if docker_compose_major_version >= 3:
119123
# compos spec version 3 and beyond
120124
deploy = spec.get("deploy", {})
@@ -133,13 +137,37 @@ def _update_resource_limits_and_reservations(
133137
resources["limits"] = limits
134138
deploy["resources"] = resources
135139
spec["deploy"] = deploy
140+
141+
nano_cpu_limits = limits["cpus"]
142+
mem_limits = limits["memory"]
136143
else:
137144
# compos spec version 2
138145
spec["mem_limit"] = f"{memory.limit}"
139146
spec["mem_reservation"] = f"{memory.reservation}"
140147
# NOTE: there is no distinction between limit and reservation, taking the higher value
141148
spec["cpus"] = float(max(cpu.limit, cpu.reservation))
142149

150+
nano_cpu_limits = spec["cpus"]
151+
mem_limits = spec["mem_limit"]
152+
153+
# Update env vars for services that need to know the current resources specs
154+
environment = spec.get("environment", [])
155+
156+
# remove any already existing env var
157+
environment = [
158+
e
159+
for e in environment
160+
if all(i not in e for i in [CPU_RESOURCE_LIMIT_KEY, MEM_RESOURCE_LIMIT_KEY])
161+
]
162+
163+
resource_limits = [
164+
f"{CPU_RESOURCE_LIMIT_KEY}={int(nano_cpu_limits*_NANO)}",
165+
f"{MEM_RESOURCE_LIMIT_KEY}={mem_limits}",
166+
]
167+
168+
environment.extend(resource_limits)
169+
spec["environment"] = environment
170+
143171

144172
def assemble_spec(
145173
app: FastAPI,

services/director-v2/tests/unit/test_modules_dynamic_sidecar_docker_compose_specs.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# pylint: disable=protected-access
33

44

5-
from typing import Any, Dict
5+
from typing import Any
66

77
import pytest
88
import yaml
@@ -12,6 +12,7 @@
1212
ServiceResourcesDict,
1313
)
1414
from pydantic import parse_obj_as
15+
from servicelib.resources import CPU_RESOURCE_LIMIT_KEY, MEM_RESOURCE_LIMIT_KEY
1516
from simcore_service_director_v2.modules.dynamic_sidecar import docker_compose_specs
1617

1718
# TESTS
@@ -98,7 +99,7 @@ def test_parse_and_export_of_compose_environment_section():
9899
],
99100
)
100101
async def test_inject_resource_limits_and_reservations(
101-
service_spec: Dict[str, Any],
102+
service_spec: dict[str, Any],
102103
service_resources: ServiceResourcesDict,
103104
) -> None:
104105
docker_compose_specs._update_resource_limits_and_reservations(
@@ -122,9 +123,21 @@ async def test_inject_resource_limits_and_reservations(
122123
)
123124
assert spec["deploy"]["resources"]["limits"]["cpus"] == cpu.limit
124125
assert spec["deploy"]["resources"]["limits"]["memory"] == f"{memory.limit}"
126+
127+
assert (
128+
f"{CPU_RESOURCE_LIMIT_KEY}={int(cpu.limit*10**9)}"
129+
in spec["environment"]
130+
)
131+
assert f"{MEM_RESOURCE_LIMIT_KEY}={memory.limit}" in spec["environment"]
125132
else:
126133
for spec in service_spec["services"].values():
127134
assert spec["mem_limit"] == f"{memory.limit}"
128135
assert spec["mem_reservation"] == f"{memory.reservation}"
129136
assert int(spec["mem_reservation"]) <= int(spec["mem_limit"])
130137
assert spec["cpus"] == max(cpu.limit, cpu.reservation)
138+
139+
assert (
140+
f"{CPU_RESOURCE_LIMIT_KEY}={int(max(cpu.limit, cpu.reservation)*10**9)}"
141+
in spec["environment"]
142+
)
143+
assert f"{MEM_RESOURCE_LIMIT_KEY}={memory.limit}" in spec["environment"]

0 commit comments

Comments
 (0)