Skip to content

Commit afed370

Browse files
authored
Merge branch 'master' into fix/reevaluate-study-menu-buttons
2 parents 9dc965a + 873fe78 commit afed370

File tree

12 files changed

+160
-70
lines changed

12 files changed

+160
-70
lines changed

packages/simcore-sdk/src/simcore_sdk/node_ports_common/file_io_utils.py

Lines changed: 24 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from aiohttp import (
1111
ClientConnectionError,
1212
ClientError,
13+
ClientPayloadError,
1314
ClientResponse,
1415
ClientResponseError,
1516
ClientSession,
@@ -31,11 +32,7 @@
3132
from tenacity.after import after_log
3233
from tenacity.asyncio import AsyncRetrying
3334
from tenacity.before_sleep import before_sleep_log
34-
from tenacity.retry import (
35-
retry_if_exception,
36-
retry_if_exception_type,
37-
retry_if_not_exception_type,
38-
)
35+
from tenacity.retry import retry_if_exception, retry_if_exception_type
3936
from tenacity.stop import stop_after_attempt
4037
from tenacity.wait import wait_exponential
4138
from tqdm import tqdm
@@ -157,7 +154,7 @@ async def _file_chunk_writer(
157154
progress_bar: ProgressBarData,
158155
):
159156
async with aiofiles.open(file, "wb") as file_pointer:
160-
async for chunk in response.content.iter_chunked(CHUNK_SIZE):
157+
while chunk := await response.content.read(CHUNK_SIZE):
161158
await file_pointer.write(chunk)
162159
if io_log_redirect_cb and pbar.update(len(chunk)):
163160
with log_catch(_logger, reraise=False):
@@ -184,28 +181,25 @@ async def download_link_to_file(
184181
progress_bar: ProgressBarData,
185182
):
186183
_logger.debug("Downloading from %s to %s", url, file_path)
187-
try:
188-
async for attempt in AsyncRetrying(
189-
reraise=True,
190-
wait=wait_exponential(min=1, max=10),
191-
stop=stop_after_attempt(num_retries),
192-
retry=retry_if_not_exception_type(
193-
(exceptions.InvalidDownloadLinkError, exceptions.TransferError)
194-
),
195-
before_sleep=before_sleep_log(_logger, logging.WARNING, exc_info=True),
196-
after=after_log(_logger, log_level=logging.ERROR),
197-
):
198-
with attempt:
199-
async with AsyncExitStack() as stack:
200-
response = await stack.enter_async_context(session.get(url))
201-
if response.status == status.HTTP_404_NOT_FOUND:
202-
raise exceptions.InvalidDownloadLinkError(url)
203-
if response.status > _VALID_HTTP_STATUS_CODES:
204-
raise exceptions.TransferError(url)
205-
file_path.parent.mkdir(parents=True, exist_ok=True)
206-
# SEE https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Length
207-
file_size = int(response.headers.get("Content-Length", 0)) or None
208-
184+
async for attempt in AsyncRetrying(
185+
reraise=True,
186+
wait=wait_exponential(min=1, max=10),
187+
stop=stop_after_attempt(num_retries),
188+
retry=retry_if_exception_type(ClientConnectionError),
189+
before_sleep=before_sleep_log(_logger, logging.WARNING, exc_info=True),
190+
after=after_log(_logger, log_level=logging.ERROR),
191+
):
192+
with attempt:
193+
async with AsyncExitStack() as stack:
194+
response = await stack.enter_async_context(session.get(url))
195+
if response.status == status.HTTP_404_NOT_FOUND:
196+
raise exceptions.InvalidDownloadLinkError(url)
197+
if response.status > _VALID_HTTP_STATUS_CODES:
198+
raise exceptions.TransferError(url)
199+
file_path.parent.mkdir(parents=True, exist_ok=True)
200+
# SEE https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Length
201+
file_size = int(response.headers.get("Content-Length", 0)) or None
202+
try:
209203
tqdm_progress = stack.enter_context(
210204
tqdm_logging_redirect(
211205
desc=f"downloading {url.path} --> {file_path.name}\n",
@@ -237,8 +231,8 @@ async def download_link_to_file(
237231
sub_progress,
238232
)
239233
_logger.debug("Download complete")
240-
except Exception as exc:
241-
raise exceptions.TransferError(url) from exc
234+
except ClientPayloadError as exc:
235+
raise exceptions.TransferError(url) from exc
242236

243237

244238
def _check_for_aws_http_errors(exc: BaseException) -> bool:

services/docker-compose.yml

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1385,10 +1385,12 @@ services:
13851385
- "--metrics.prometheus.entryPoint=metrics"
13861386
- "--entryPoints.http.address=:80"
13871387
- "--entryPoints.http.forwardedHeaders.insecure"
1388-
- "--entryPoints.http.transport.respondingTimeouts.readTimeout=21600s" #6h, for https://github.com/traefik/traefik/issues/10805 - "--entryPoints.simcore_api.address=:10081"
1388+
- "--entryPoints.http.transport.respondingTimeouts.readTimeout=21600s" #6h, for https://github.com/traefik/traefik/issues/10805 large file uploads
1389+
- "--entryPoints.http.transport.respondingTimeouts.writeTimeout=21600s" #6h, for https://github.com/traefik/traefik/issues/10805 large file downloads
13891390
- "--entryPoints.simcore_api.address=:10081"
13901391
- "--entryPoints.simcore_api.forwardedHeaders.insecure"
1391-
- "--entryPoints.simcore_api.transport.respondingTimeouts.readTimeout=21600s" #6h, for https://github.com/traefik/traefik/issues/10805
1392+
- "--entryPoints.simcore_api.transport.respondingTimeouts.readTimeout=21600s" #6h, for https://github.com/traefik/traefik/issues/10805 large file uploads
1393+
- "--entryPoints.simcore_api.transport.respondingTimeouts.writeTimeout=21600s" #6h, for https://github.com/traefik/traefik/issues/10805 large file downloads
13921394
- "--entryPoints.traefik_monitor.address=:8080"
13931395
- "--entryPoints.traefik_monitor.forwardedHeaders.insecure"
13941396
- "--providers.swarm.endpoint=unix:///var/run/docker.sock"
@@ -1401,6 +1403,14 @@ services:
14011403
- "--tracing.addinternals"
14021404
- "--tracing.otlp=true"
14031405
- "--tracing.otlp.http=true"
1406+
healthcheck:
1407+
# NOTE: this healthcheck to check if traefik is up and running must be run on the ping entrypoint defined in command!
1408+
test: traefik healthcheck --ping --ping.entryPoint=ping --entryPoints.ping.address=:9082
1409+
interval: 10s
1410+
timeout: 5s
1411+
retries: 5
1412+
start_period: 10s
1413+
start_interval: 1s
14041414
volumes:
14051415
# So that Traefik can listen to the Docker events
14061416
- /var/run/docker.sock:/var/run/docker.sock

services/static-webserver/client/source/class/osparc/editor/HtmlEditor.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,7 @@ qx.Class.define("osparc.editor.HtmlEditor", {
2626

2727
this.getChildControl("preview-html");
2828
this.getChildControl("subtitle").set({
29-
value: this.tr("Supports HTML"),
30-
url: "https://en.wikipedia.org/wiki/HTML",
29+
value: this.tr("Supports HTML")
3130
});
3231
},
3332

services/static-webserver/client/source/class/osparc/editor/MarkdownEditor.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,7 @@ qx.Class.define("osparc.editor.MarkdownEditor", {
3131

3232
this.getChildControl("preview-markdown");
3333
this.getChildControl("subtitle").set({
34-
value: this.tr("Markdown supported"),
35-
url: "https://en.wikipedia.org/wiki/Markdown",
34+
value: this.tr("Markdown supported")
3635
});
3736
},
3837

services/static-webserver/client/source/class/osparc/editor/TextEditor.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,13 +81,15 @@ qx.Class.define("osparc.editor.TextEditor", {
8181
writePage.add(control, {
8282
flex: 1
8383
});
84-
const subtitle = this.getChildControl("subtitle");
84+
const subtitle = this.getChildControl("subtitle").set({
85+
value: this.tr("Supports HTML")
86+
});
8587
writePage.add(subtitle);
8688
tabs.add(writePage);
8789
break;
8890
}
8991
case "subtitle":
90-
control = new osparc.ui.basic.LinkLabel().set({
92+
control = new qx.ui.basic.Label().set({
9193
font: "text-12"
9294
});
9395
this._add(control);

services/static-webserver/client/source/class/osparc/info/CommentUI.js

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,10 @@ qx.Class.define("osparc.info.CommentUI", {
113113

114114
__buildLayout: function() {
115115
const thumbnail = this.getChildControl("thumbnail");
116+
thumbnail.setSource(osparc.utils.Avatar.emailToThumbnail("", "", 32));
116117

117118
const userName = this.getChildControl("user-name");
119+
userName.setValue("Unknown");
118120

119121
const date = new Date(this.__comment["modified"]);
120122
const date2 = osparc.utils.Utils.formatDateAndTime(date);
@@ -129,14 +131,7 @@ qx.Class.define("osparc.info.CommentUI", {
129131
if (user) {
130132
thumbnail.setSource(user.getThumbnail());
131133
userName.setValue(user.getLabel());
132-
} else {
133-
thumbnail.setSource(osparc.utils.Avatar.emailToThumbnail());
134-
userName.setValue("Unknown user");
135134
}
136-
})
137-
.catch(() => {
138-
thumbnail.setSource(osparc.utils.Avatar.emailToThumbnail());
139-
userName.setValue("Unknown user");
140135
});
141136

142137
this.getChildControl("spacer");

services/static-webserver/client/source/class/osparc/utils/Avatar.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,12 @@ qx.Class.define("osparc.utils.Avatar", {
3434
type: "static",
3535

3636
statics: {
37-
emailToThumbnail: function(email = "", username = "??", size = 32) {
37+
emailToThumbnail: function(email, username) {
38+
return this.__getUrl(email, username, 32);
39+
},
40+
41+
__getUrl: function(email, username, size = 100) {
42+
email = email || "";
3843
// MD5 (Message-Digest Algorithm) by WebToolkit
3944
const MD5 = function(s) {
4045
function L(k, d) {

services/static-webserver/client/source/resource/osparc/ui_config.json

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -156,11 +156,6 @@
156156
"title": "${replace_me_product_name}",
157157
"newStudyLabel": "New Project",
158158
"idToWidget": "startS4LButton"
159-
}, {
160-
"resourceType": "service",
161-
"expectedKey": "simcore/services/dynamic/s4l-ui-framework",
162-
"title": "Sim4Life.framework",
163-
"newStudyLabel": "Sim4Life.framework"
164159
}]
165160
}
166161
},

services/web/server/src/simcore_service_webserver/catalog/_catalog_rest_client_service.py

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,15 @@
2121
from models_library.services_types import ServiceKey, ServiceVersion
2222
from models_library.users import UserID
2323
from pydantic import TypeAdapter
24-
from servicelib.aiohttp import status
2524
from servicelib.aiohttp.client_session import get_client_session
2625
from servicelib.rest_constants import X_PRODUCT_NAME_HEADER
26+
from simcore_service_webserver.catalog.errors import (
27+
CatalogConnectionError,
28+
CatalogResponseError,
29+
)
2730
from yarl import URL
2831

2932
from .._meta import api_version_prefix
30-
from ._constants import MSG_CATALOG_SERVICE_NOT_FOUND, MSG_CATALOG_SERVICE_UNAVAILABLE
3133
from .settings import CatalogSettings, get_plugin_settings
3234

3335
_logger = logging.getLogger(__name__)
@@ -51,16 +53,17 @@ def _handle_client_exceptions(app: web.Application) -> Iterator[ClientSession]:
5153
yield session
5254

5355
except ClientResponseError as err:
54-
if err.status == status.HTTP_404_NOT_FOUND:
55-
raise web.HTTPNotFound(text=MSG_CATALOG_SERVICE_NOT_FOUND) from err
56-
raise web.HTTPServiceUnavailable(
57-
reason=MSG_CATALOG_SERVICE_UNAVAILABLE
56+
raise CatalogResponseError(
57+
status=err.status,
58+
message=err.message,
59+
headers=err.headers,
60+
request_info=err.request_info,
5861
) from err
5962

6063
except (TimeoutError, ClientConnectionError) as err:
61-
_logger.debug("Request to catalog service failed: %s", err)
62-
raise web.HTTPServiceUnavailable(
63-
reason=MSG_CATALOG_SERVICE_UNAVAILABLE
64+
raise CatalogConnectionError(
65+
message=str(err),
66+
request_info=getattr(err, "request_info", None),
6467
) from err
6568

6669

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
from typing import Final
22

3-
MSG_CATALOG_SERVICE_UNAVAILABLE: Final[
4-
str
5-
] = "Currently catalog service is unavailable, please try again later"
3+
from ..constants import MSG_TRY_AGAIN_OR_SUPPORT
4+
5+
MSG_CATALOG_SERVICE_UNAVAILABLE: Final[str] = (
6+
# Most likely the director service is down or misconfigured so the user is asked to try again later.
7+
"This service is temporarily unavailable. The incident was logged and will be investigated. "
8+
+ MSG_TRY_AGAIN_OR_SUPPORT
9+
)
10+
611

712
MSG_CATALOG_SERVICE_NOT_FOUND: Final[str] = "Not Found"

0 commit comments

Comments
 (0)