Skip to content

Commit 75afd7f

Browse files
authored
šŸ› Is638/ fixes dy-sidecar docker-compose process down command and timeout (ITISFoundation#3182)
- closes Make docker_compose_down reliable ITISFoundation#3172 - fixes ``async_command`` timeout feature
1 parent f1e2d74 commit 75afd7f

File tree

16 files changed

+418
-153
lines changed

16 files changed

+418
-153
lines changed
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.1.0
1+
1.1.1

ā€Žservices/dynamic-sidecar/openapi.jsonā€Ž

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"info": {
44
"title": "simcore-service-dynamic-sidecar",
55
"description": " Implements a sidecar service to manage user's dynamic/interactive services",
6-
"version": "1.1.0"
6+
"version": "1.1.1"
77
},
88
"servers": [
99
{
@@ -103,9 +103,9 @@
103103
"required": false,
104104
"schema": {
105105
"title": "Command Timeout",
106-
"type": "number",
106+
"type": "integer",
107107
"description": "docker-compose up command timeout run as a background",
108-
"default": 3600.0
108+
"default": 3600
109109
},
110110
"name": "command_timeout",
111111
"in": "query"
@@ -115,9 +115,9 @@
115115
"required": false,
116116
"schema": {
117117
"title": "Validation Timeout",
118-
"type": "number",
118+
"type": "integer",
119119
"description": "docker-compose config timeout (EXPERIMENTAL)",
120-
"default": 60.0
120+
"default": 60
121121
},
122122
"name": "validation_timeout",
123123
"in": "query"
@@ -168,9 +168,9 @@
168168
"required": false,
169169
"schema": {
170170
"title": "Command Timeout",
171-
"type": "number",
171+
"type": "integer",
172172
"description": "docker-compose down command timeout default (EXPERIMENTAL)",
173-
"default": 10.0
173+
"default": 10
174174
},
175175
"name": "command_timeout",
176176
"in": "query"
@@ -600,9 +600,9 @@
600600
"required": false,
601601
"schema": {
602602
"title": "Command Timeout",
603-
"type": "number",
603+
"type": "integer",
604604
"description": "docker-compose stop command timeout default",
605-
"default": 10.0
605+
"default": 10
606606
},
607607
"name": "command_timeout",
608608
"in": "query"

ā€Žservices/dynamic-sidecar/requirements/_base.inā€Ž

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ aiofiles
3030
docker-compose
3131
fastapi
3232
httpx
33+
psutil
3334
pydantic
3435
python-magic # file type identification library. See 'magic.from_file(...)'
3536
PyYAML

ā€Žservices/dynamic-sidecar/requirements/_base.txtā€Ž

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,8 @@ paramiko==2.11.0
209209
# docker
210210
pint==0.19.2
211211
# via -r requirements/../../../packages/simcore-sdk/requirements/_base.in
212+
psutil==5.9.1
213+
# via -r requirements/_base.in
212214
psycopg2-binary==2.9.3
213215
# via
214216
# aiopg

ā€Žservices/dynamic-sidecar/setup.cfgā€Ž

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[bumpversion]
2-
current_version = 1.1.0
2+
current_version = 1.1.1
33
commit = True
44
message = services/dynamic-sidecar version: {current_version} → {new_version}
55
tag = False

ā€Žservices/dynamic-sidecar/src/simcore_service_dynamic_sidecar/api/containers.pyā€Ž

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,11 @@
1212
from pydantic import BaseModel
1313
from servicelib.fastapi.requests_decorators import cancel_on_disconnect
1414

15-
from ..core.docker_compose_utils import docker_compose_down, docker_compose_up
15+
from ..core.docker_compose_utils import (
16+
docker_compose_down,
17+
docker_compose_rm,
18+
docker_compose_up,
19+
)
1620
from ..core.docker_logs import start_log_fetching, stop_log_fetching
1721
from ..core.docker_utils import docker_client
1822
from ..core.rabbitmq import RabbitMQ
@@ -50,18 +54,21 @@ async def _task_docker_compose_up_and_send_message(
5054
app: FastAPI,
5155
application_health: ApplicationHealth,
5256
rabbitmq: RabbitMQ,
53-
command_timeout: float,
57+
command_timeout: int,
5458
) -> None:
5559
# building is a security risk hence is disabled via "--no-build" parameter
5660
await send_message(rabbitmq, "starting service containers")
5761
assert shared_store.compose_spec # nosec
5862

5963
with directory_watcher_disabled(app):
64+
# prunes first stopped containers
65+
await docker_compose_rm(shared_store.compose_spec, settings)
66+
6067
r = await docker_compose_up(
61-
shared_store, settings, command_timeout=command_timeout
68+
shared_store.compose_spec, settings, timeout=command_timeout
6269
)
6370

64-
message = f"Finished docker-compose up with output\n{r.decoded_stdout}"
71+
message = f"Finished docker-compose up with output\n{r.message}"
6572

6673
if r.success:
6774
await send_message(rabbitmq, "service containers started")
@@ -117,11 +124,11 @@ async def create_containers(
117124
request: Request,
118125
containers_create: ContainersCreate,
119126
background_tasks: BackgroundTasks,
120-
command_timeout: float = Query(
121-
3600.0, description="docker-compose up command timeout run as a background"
127+
command_timeout: int = Query(
128+
3600, description="docker-compose up command timeout run as a background"
122129
),
123-
validation_timeout: float = Query(
124-
60.0, description="docker-compose config timeout (EXPERIMENTAL)"
130+
validation_timeout: int = Query(
131+
60, description="docker-compose config timeout (EXPERIMENTAL)"
125132
),
126133
settings: DynamicSidecarSettings = Depends(get_settings),
127134
shared_store: SharedStore = Depends(get_shared_store),
@@ -176,8 +183,8 @@ async def create_containers(
176183
},
177184
)
178185
async def runs_docker_compose_down(
179-
command_timeout: float = Query(
180-
10.0, description="docker-compose down command timeout default (EXPERIMENTAL)"
186+
command_timeout: int = Query(
187+
10, description="docker-compose down command timeout default (EXPERIMENTAL)"
181188
),
182189
settings: DynamicSidecarSettings = Depends(get_settings),
183190
shared_store: SharedStore = Depends(get_shared_store),
@@ -193,24 +200,28 @@ async def runs_docker_compose_down(
193200
)
194201

195202
result = await docker_compose_down(
196-
shared_store=shared_store,
197-
settings=settings,
198-
command_timeout=command_timeout,
203+
shared_store.compose_spec,
204+
settings,
205+
timeout=min(command_timeout, settings.DYNAMIC_SIDECAR_STOP_AND_REMOVE_TIMEOUT),
199206
)
200207

201208
for container_name in shared_store.container_names:
202209
await stop_log_fetching(app, container_name)
203210

211+
await docker_compose_rm(shared_store.compose_spec, settings)
212+
204213
if not result.success:
205214
logger.warning(
206215
"docker-compose down command finished with errors\n%s",
207-
result.decoded_stdout,
208-
)
209-
raise HTTPException(
210-
status.HTTP_422_UNPROCESSABLE_ENTITY, detail=result.decoded_stdout
216+
result.message,
211217
)
218+
raise HTTPException(status.HTTP_422_UNPROCESSABLE_ENTITY, detail=result.message)
219+
220+
# removing compose-file spec
221+
assert result.success # nosec
222+
shared_store.clear()
212223

213-
return result.decoded_stdout
224+
return result.message
214225

215226

216227
@containers_router.get(

ā€Žservices/dynamic-sidecar/src/simcore_service_dynamic_sidecar/api/containers_extension.pyā€Ž

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -270,8 +270,8 @@ async def push_output_ports(
270270
@cancel_on_disconnect
271271
async def restarts_containers(
272272
request: Request,
273-
command_timeout: float = Query(
274-
10.0, description="docker-compose stop command timeout default"
273+
command_timeout: int = Query(
274+
10, description="docker-compose stop command timeout default"
275275
),
276276
app: FastAPI = Depends(get_application),
277277
settings: DynamicSidecarSettings = Depends(get_settings),
@@ -293,16 +293,16 @@ async def restarts_containers(
293293
await stop_log_fetching(app, container_name)
294294

295295
result = await docker_compose_restart(
296-
shared_store.compose_spec, settings, command_timeout=command_timeout
296+
shared_store.compose_spec,
297+
settings,
298+
timeout=min(command_timeout, settings.DYNAMIC_SIDECAR_STOP_AND_REMOVE_TIMEOUT),
297299
)
298300

299301
if not result.success:
300302
logger.warning(
301-
"docker-compose restart finished with errors\n%s", result.decoded_stdout
302-
)
303-
raise HTTPException(
304-
status.HTTP_422_UNPROCESSABLE_ENTITY, detail=result.decoded_stdout
303+
"docker-compose restart finished with errors\n%s", result.message
305304
)
305+
raise HTTPException(status.HTTP_422_UNPROCESSABLE_ENTITY, detail=result.message)
306306

307307
for container_name in shared_store.container_names:
308308
await start_log_fetching(app, container_name)

ā€Žservices/dynamic-sidecar/src/simcore_service_dynamic_sidecar/core/application.pyā€Ž

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ class AppState:
6060
}
6161

6262
def __init__(self, initialized_app: FastAPI):
63-
# guarantees app states are in place
63+
# Ensures states are initialized upon construction
6464
errors = [
6565
"app.state.{name}"
6666
for name, type_ in AppState._STATES.items()
@@ -84,13 +84,13 @@ def mounted_volumes(self) -> MountedVolumes:
8484
return self._app.state.mounted_volumes
8585

8686
@property
87-
def shared_store(self) -> SharedStore:
87+
def _shared_store(self) -> SharedStore:
8888
assert isinstance(self._app.state.shared_store, SharedStore) # nosec
8989
return self._app.state.shared_store
9090

9191
@property
9292
def compose_spec(self) -> Optional[str]:
93-
return self.shared_store.compose_spec
93+
return self._shared_store.compose_spec
9494

9595

9696
def setup_logger(settings: DynamicSidecarSettings):
@@ -161,18 +161,19 @@ async def _on_startup() -> None:
161161

162162
async def _on_shutdown() -> None:
163163
if docker_compose_yaml := app_state.compose_spec:
164-
logger.info("Removing spawned containers%s", docker_compose_yaml)
164+
logger.info("Removing spawned containers")
165165

166166
result = await docker_compose_down(
167-
app.state.shared_store,
167+
docker_compose_yaml,
168168
app.state.settings,
169-
command_timeout=app.state.settings.DYNAMIC_SIDECAR_DOCKER_COMPOSE_DOWN_TIMEOUT,
169+
# NOTE: in the event of a SIGTERM, there is a limited time to cleanup
170+
timeout=app.state.settings.DYNAMIC_SIDECAR_DOCKER_COMPOSE_DOWN_TIMEOUT,
170171
)
171172

172173
logger.log(
173174
logging.INFO if result.success else logging.ERROR,
174175
"Removed spawned containers:\n%s",
175-
result.decoded_stdout,
176+
result.message,
176177
)
177178
# FINISHED
178179
print(APP_FINISHED_BANNER_MSG, flush=True)

0 commit comments

Comments
Ā (0)