Skip to content

Commit 7ef5279

Browse files
authored
✨🐛Webserver: enable socketio horizontal scaling + ensure only 1 update goes through (⚠️ devops) (#4286)
1 parent a25c044 commit 7ef5279

38 files changed

+472
-283
lines changed

.env-wb-db-event-listener

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#
2+
# Explicit plugins DISABLED in the webserver to create a garbage-collector
3+
# Docs plugins config of services/web/server/src/simcore_service_webserver/application_settings.py
4+
#
5+
6+
7+
WEBSERVER_ACTIVITY=null
8+
WEBSERVER_CATALOG=null
9+
WEBSERVER_NOTIFICATIONS=0
10+
# WEBSERVER_DB_LISTENER=1 explicitely enabled in docker-compose
11+
WEBSERVER_DIAGNOSTICS=null
12+
#WEBSERVER_DIRECTOR_V2 from .env
13+
WEBSERVER_DIRECTOR=null
14+
WEBSERVER_EMAIL=null
15+
WEBSERVER_EXPORTER=null
16+
WEBSERVER_FRONTEND=null
17+
WEBSERVER_GARBAGE_COLLECTOR=null
18+
WEBSERVER_LOGIN=null
19+
WEBSERVER_PROJECTS=null
20+
#WEBSERVER_RABBITMQ from .env
21+
WEBSERVER_REDIS=null
22+
#WEBSERVER_REST needed for the healthcheck
23+
#WEBSERVER_RESOURCE_MANAGER from .env
24+
WEBSERVER_SCICRUNCH=null
25+
WEBSERVER_STATICWEB=null
26+
WEBSERVER_STORAGE=null
27+
WEBSERVER_STUDIES_DISPATCHER=null
28+
WEBSERVER_TRACING=null
29+
# --------
30+
WEBSERVER_CLUSTERS=0
31+
WEBSERVER_GROUPS=0
32+
WEBSERVER_META_MODELING=0
33+
WEBSERVER_PRODUCTS=0
34+
WEBSERVER_PUBLICATIONS=0
35+
#WEBSERVER_SOCKETIO=1 explicitely enabled in docker-compose
36+
WEBSERVER_STUDIES_DISPATCHER=null
37+
WEBSERVER_TAGS=0
38+
WEBSERVER_USERS=0
39+
WEBSERVER_VERSION_CONTROL=0

.env-wb-garbage-collector

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,14 @@
77
WEBSERVER_ACTIVITY=null
88
WEBSERVER_CATALOG=null
99
WEBSERVER_NOTIFICATIONS=0
10+
WEBSERVER_DB_LISTENER=0
1011
WEBSERVER_DIAGNOSTICS=null
1112
#WEBSERVER_DIRECTOR_V2 from .env
1213
WEBSERVER_DIRECTOR=null
1314
WEBSERVER_EMAIL=null
1415
WEBSERVER_EXPORTER=null
1516
WEBSERVER_FRONTEND=null
16-
#WEBSERVER_GARBAGE_COLLECTOR explicit in
17+
#WEBSERVER_GARBAGE_COLLECTOR explicitely enabled in docker-compose
1718
WEBSERVER_LOGIN=null
1819
WEBSERVER_PROJECTS=null
1920
#WEBSERVER_REDIS from .env

packages/pytest-simcore/src/pytest_simcore/postgres_service.py

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
import sqlalchemy as sa
1010
import tenacity
1111
from servicelib.json_serialization import json_dumps
12-
from sqlalchemy.orm import sessionmaker
1312
from tenacity.stop import stop_after_delay
1413
from tenacity.wait import wait_fixed
1514

@@ -28,7 +27,9 @@ def execute_queries(
2827
with postgres_engine.connect() as con:
2928
for statement in sql_statements:
3029
try:
31-
con.execution_options(autocommit=True).execute(statement)
30+
with con.begin():
31+
con.execute(statement)
32+
3233
except Exception as e: # pylint: disable=broad-except
3334
# when running tests initially the TEMPLATE_DB_TO_RESTORE dose not exist and will cause an error
3435
# which can safely be ignored. The debug message is here to catch future errors which and
@@ -235,15 +236,3 @@ def postgres_host_config(
235236
"POSTGRES_ENDPOINT", f"{postgres_dsn['host']}:{postgres_dsn['port']}"
236237
)
237238
return postgres_dsn
238-
239-
240-
@pytest.fixture(scope="module")
241-
def postgres_session(postgres_db: sa.engine.Engine) -> Iterator[sa.orm.session.Session]:
242-
from sqlalchemy.orm.session import Session
243-
244-
Session_cls = sessionmaker(postgres_db)
245-
session: Session = Session_cls()
246-
247-
yield session
248-
249-
session.close() # pylint: disable=no-member

packages/pytest-simcore/src/pytest_simcore/rabbit_service.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import pytest
1313
import tenacity
1414
from servicelib.rabbitmq import RabbitMQClient
15+
from settings_library.basic_types import PortInt
1516
from settings_library.rabbit import RabbitSettings
1617
from tenacity.before_sleep import before_sleep_log
1718
from tenacity.stop import stop_after_attempt
@@ -48,7 +49,7 @@ async def rabbit_settings(
4849
RABBIT_USER=testing_environ_vars["RABBIT_USER"],
4950
RABBIT_PASSWORD=testing_environ_vars["RABBIT_PASSWORD"],
5051
RABBIT_HOST=get_localhost_ip(),
51-
RABBIT_PORT=int(port),
52+
RABBIT_PORT=PortInt(port),
5253
)
5354

5455
await wait_till_rabbit_responsive(settings.dsn)

packages/pytest-simcore/src/pytest_simcore/websocket_client.py

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
# pylint:disable=redefined-outer-name
44

55
import logging
6-
from typing import AsyncIterable, Awaitable, Callable, Optional
6+
from typing import AsyncIterable, Awaitable, Callable
77
from uuid import uuid4
88

99
import pytest
@@ -25,8 +25,8 @@ def _create() -> str:
2525

2626

2727
@pytest.fixture()
28-
def socketio_url_factory(client) -> Callable[[Optional[TestClient]], str]:
29-
def _create(client_override: Optional[TestClient] = None) -> str:
28+
def socketio_url_factory(client) -> Callable[[TestClient | None], str]:
29+
def _create(client_override: TestClient | None = None) -> str:
3030
SOCKET_IO_PATH = "/socket.io/"
3131
return str((client_override or client).make_url(SOCKET_IO_PATH))
3232

@@ -36,8 +36,8 @@ def _create(client_override: Optional[TestClient] = None) -> str:
3636
@pytest.fixture()
3737
async def security_cookie_factory(
3838
client: TestClient,
39-
) -> Callable[[Optional[TestClient]], Awaitable[str]]:
40-
async def _create(client_override: Optional[TestClient] = None) -> str:
39+
) -> Callable[[TestClient | None], Awaitable[str]]:
40+
async def _create(client_override: TestClient | None = None) -> str:
4141
# get the cookie by calling the root entrypoint
4242
resp = await (client_override or client).get("/v0/")
4343
data, error = await assert_status(resp, web.HTTPOk)
@@ -60,14 +60,13 @@ async def socketio_client_factory(
6060
security_cookie_factory: Callable,
6161
client_session_id_factory: Callable,
6262
) -> AsyncIterable[
63-
Callable[[Optional[str], Optional[TestClient]], Awaitable[socketio.AsyncClient]]
63+
Callable[[str | None, TestClient | None], Awaitable[socketio.AsyncClient]]
6464
]:
6565
clients: list[socketio.AsyncClient] = []
6666

6767
async def _connect(
68-
client_session_id: Optional[str] = None, client: Optional[TestClient] = None
68+
client_session_id: str | None = None, client: TestClient | None = None
6969
) -> socketio.AsyncClient:
70-
7170
if client_session_id is None:
7271
client_session_id = client_session_id_factory()
7372

@@ -86,7 +85,7 @@ async def _connect(
8685
headers.update({"Cookie": cookie})
8786

8887
print(f"--> Connecting socketio client to {url} ...")
89-
await sio.connect(url, headers=headers)
88+
await sio.connect(url, headers=headers, wait_timeout=10)
9089
assert sio.sid
9190
print("... connection done")
9291
clients.append(sio)

packages/settings-library/src/settings_library/rabbit.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from functools import cached_property
22

3+
from pydantic import parse_obj_as
34
from pydantic.networks import AnyUrl
45
from pydantic.types import SecretStr
56

@@ -14,7 +15,7 @@ class RabbitDsn(AnyUrl):
1415
class RabbitSettings(BaseCustomSettings):
1516
# host
1617
RABBIT_HOST: str
17-
RABBIT_PORT: PortInt = 5672
18+
RABBIT_PORT: PortInt = parse_obj_as(PortInt, 5672)
1819

1920
# auth
2021
RABBIT_USER: str

services/docker-compose.devel.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,11 @@ services:
8686
SC_BOOT_MODE: debug-ptvsd
8787
WEBSERVER_LOGLEVEL: ${LOG_LEVEL:-DEBUG}
8888

89+
wb-db-event-listener:
90+
volumes: *webserver-volumes-dev
91+
environment:
92+
<<: *webserver-environment-dev
93+
8994
wb-garbage-collector:
9095
volumes: *webserver-volumes-dev
9196
environment:

services/docker-compose.local.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,15 @@ services:
8484
- traefik.http.routers.${SWARM_STACK_NAME}_webserver_local.priority=3
8585
- traefik.http.routers.${SWARM_STACK_NAME}_webserver_local.middlewares=${SWARM_STACK_NAME}_gzip@docker, ${SWARM_STACK_NAME_NO_HYPHEN}_sslheader@docker, ${SWARM_STACK_NAME}_webserver_retry
8686

87+
wb-db-event-listener:
88+
environment:
89+
SC_BOOT_MODE: ${SC_BOOT_MODE:-default}
90+
WEBSERVER_LOGLEVEL: ${LOG_LEVEL:-INFO}
91+
REST_SWAGGER_API_DOC_ENABLED: 1
92+
ports:
93+
- "8080"
94+
- "3013:3000"
95+
8796
wb-garbage-collector:
8897
environment:
8998
SC_BOOT_MODE: ${SC_BOOT_MODE:-default}

services/docker-compose.yml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,7 @@ services:
263263
STORAGE_HOST: ${STORAGE_HOST:-storage}
264264
STORAGE_PORT: ${STORAGE_PORT:-8080}
265265
SWARM_STACK_NAME: ${SWARM_STACK_NAME:-simcore}
266+
WEBSERVER_DB_LISTENER: 0
266267
WEBSERVER_GARBAGE_COLLECTOR: "null"
267268
WEBSERVER_LOGLEVEL: ${LOG_LEVEL:-WARNING}
268269
env_file:
@@ -297,6 +298,27 @@ services:
297298
networks:
298299
- default
299300
- interactive_services_subnet
301+
wb-db-event-listener:
302+
image: ${DOCKER_REGISTRY:-itisfoundation}/webserver:${DOCKER_IMAGE_TAG:-latest}
303+
init: true
304+
hostname: "{{.Node.Hostname}}-{{.Service.Name}}-{{.Task.Slot}}"
305+
environment:
306+
<<: *webserver-environment
307+
WEBSERVER_DB_LISTENER: 1
308+
WEBSERVER_SOCKETIO: 1
309+
env_file:
310+
- ../.env
311+
- ../.env-wb-db-event-listener
312+
deploy:
313+
# NOTE: https://github.com/ITISFoundation/osparc-simcore/pull/4286
314+
# NOTE: this MUSTN'T change, or weird things might happen
315+
# this will stay until all legacy dynamic services are gone.
316+
replicas: 1
317+
placement:
318+
constraints:
319+
- node.platform.os == linux
320+
networks:
321+
- default
300322

301323
wb-garbage-collector:
302324
image: ${DOCKER_REGISTRY:-itisfoundation}/webserver:${DOCKER_IMAGE_TAG:-latest}

services/storage/Dockerfile

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -132,10 +132,10 @@ COPY --from=prod-only-deps --chown=scu:scu ${VIRTUAL_ENV} ${VIRTUAL_ENV}
132132
COPY --chown=scu:scu services/storage/docker services/storage/docker
133133
RUN chmod +x services/storage/docker/*.sh
134134

135-
HEALTHCHECK --interval=30s \
136-
--timeout=120s \
137-
--start-period=30s \
138-
--retries=3 \
135+
HEALTHCHECK --interval=10s \
136+
--timeout=15s \
137+
--start-period=5s \
138+
--retries=5 \
139139
CMD ["python3", "/home/scu/services/storage/docker/healthcheck.py", "http://localhost:8080/v0/"]
140140

141141

0 commit comments

Comments
 (0)