Skip to content

Commit 01bdad6

Browse files
authored
Merge pull request #725 from cylc/1.7.x-sync
🤖 Merge 1.7.x-sync into master
2 parents c0806f5 + 1e183e1 commit 01bdad6

File tree

112 files changed

+821
-757
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

112 files changed

+821
-757
lines changed

CHANGES.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,18 @@ $ towncrier create <PR-number>.<break|feat|fix>.md --content "Short description"
1212

1313
<!-- towncrier release notes start -->
1414

15+
## cylc-uiserver-1.7.1 (Released 2025-09-04)
16+
17+
[Updated cylc-ui to 2.9.0](https://github.com/cylc/cylc-ui/blob/master/CHANGES.md)
18+
19+
### 🚀 Enhancements
20+
21+
[#715](https://github.com/cylc/cylc-uiserver/pull/715) - Improve the ordering of numeric log file, such as those produced by rose-bunch, when listing job log files in the UI.
22+
23+
### 🔧 Fixes
24+
25+
[#714](https://github.com/cylc/cylc-uiserver/pull/714) - Handle websocket closed error showing as traceback in the log.
26+
1527
## cylc-uiserver-1.7.0 (Released 2025-07-24)
1628

1729
[Updated cylc-ui to 2.8.0](https://github.com/cylc/cylc-ui/blob/master/CHANGES.md)

CONTRIBUTING.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ below.
6060
- Christopher Bennett
6161
- Mark Dawson
6262
- Min RK
63+
- James Frost
6364
<!-- end-shortlog -->
6465

6566
(All contributors are identifiable with email addresses in the git version

cylc/uiserver/graphql/tornado_ws.py

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,15 @@
6262
GQL_COMPLETE = "complete" # Server -> Client
6363
GQL_STOP = "stop" # Client -> Server
6464

65+
REQ_HEADER_INFO = {
66+
'Host',
67+
'User-Agent',
68+
'Origin',
69+
'Connection',
70+
'Sec-Websocket-Version',
71+
'Sec-Websocket-Protocol',
72+
}
73+
6574

6675
class ConnectionClosedException(Exception):
6776
pass
@@ -106,7 +115,9 @@ def closed(self):
106115
return self.ws.close_code is not None
107116

108117
async def close(self, code):
109-
await self.ws.close(code)
118+
ws_close = self.ws.close(code)
119+
if ws_close is not None:
120+
await ws_close
110121

111122
def remember_task(self, task):
112123
self.pending_tasks.add(task)
@@ -325,15 +336,40 @@ async def on_start(self, connection_context, op_id, params):
325336
finally:
326337
if iterator:
327338
await iterator.aclose()
328-
await self.send_message(connection_context, op_id, GQL_COMPLETE)
339+
with suppress(WebSocketClosedError):
340+
await self.send_message(connection_context, op_id, GQL_COMPLETE)
329341
await connection_context.unsubscribe(op_id)
330342
await self.on_operation_complete(connection_context, op_id)
331343

332344
async def send_message(
333345
self, connection_context, op_id=None, op_type=None, payload=None
334346
):
335347
message = self.build_message(op_id, op_type, payload)
336-
return await connection_context.send(message)
348+
try:
349+
return await connection_context.send(message)
350+
except WebSocketClosedError:
351+
resolvers = connection_context.request_context.get('resolvers')
352+
if resolvers is not None:
353+
request = connection_context.request_context.get('request')
354+
headers = {}
355+
headers.update(getattr(request, 'headers', {}))
356+
resolvers.log.warning(
357+
'[GraphQL WS] Websocket closed on send'
358+
f' (Op.Type: {op_type}, Op.ID: {op_id})'
359+
f' to remote IP: {request.remote_ip}'
360+
)
361+
headers_string = ''
362+
for key, val in headers.items():
363+
if key in REQ_HEADER_INFO:
364+
headers_string += f' {key}: {val} \n'
365+
resolvers.log.debug(
366+
'Websocket closed on send, with request context: \n'
367+
f' Remote IP: {request.remote_ip} \n'
368+
' Request Header Info: \n'
369+
f'{headers_string}'
370+
)
371+
# Raise exception, in order to exit the on_start subscription loop.
372+
raise
337373

338374
def build_message(self, _id, op_type, payload):
339375
message = {}
@@ -381,8 +417,9 @@ async def send_error(
381417

382418
error_payload = {"message": str(error)}
383419

384-
return await self.send_message(
385-
connection_context, op_id, error_type, error_payload)
420+
with suppress(WebSocketClosedError):
421+
return await self.send_message(
422+
connection_context, op_id, error_type, error_payload)
386423

387424
async def on_message(self, connection_context, message):
388425
try:

cylc/uiserver/resolvers.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
from cylc.flow.id import Tokens
5252
from cylc.flow.network.resolvers import BaseResolvers
5353
from cylc.flow.scripts.clean import CleanOptions, run
54+
from cylc.flow.util import natural_sort_key
5455

5556
if TYPE_CHECKING:
5657
from concurrent.futures import Executor
@@ -506,6 +507,7 @@ async def cat_log_files(cls, id_: Tokens, log: 'Logger') -> List[str]:
506507
# this means that the most recent log file rotations
507508
# will be at the top of the list
508509
out.decode().splitlines(),
510+
key=natural_sort_key,
509511
reverse=True,
510512
)
511513
return []

cylc/uiserver/ui/2.8.0/assets/Dashboard-iZtRnvU3.js

Lines changed: 0 additions & 35 deletions
This file was deleted.

cylc/uiserver/ui/2.8.0/assets/Graph-DjGaoGFs.js

Lines changed: 0 additions & 122 deletions
This file was deleted.

cylc/uiserver/ui/2.8.0/assets/Guide-Dm6HFD0j.js

Lines changed: 0 additions & 1 deletion
This file was deleted.

0 commit comments

Comments
 (0)