Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,18 @@ $ towncrier create <PR-number>.<break|feat|fix>.md --content "Short description"

<!-- towncrier release notes start -->

## cylc-uiserver-1.7.1 (Released 2025-09-04)

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

### 🚀 Enhancements

[#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.

### 🔧 Fixes

[#714](https://github.com/cylc/cylc-uiserver/pull/714) - Handle websocket closed error showing as traceback in the log.

## cylc-uiserver-1.7.0 (Released 2025-07-24)

[Updated cylc-ui to 2.8.0](https://github.com/cylc/cylc-ui/blob/master/CHANGES.md)
Expand Down
1 change: 1 addition & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ below.
- Christopher Bennett
- Mark Dawson
- Min RK
- James Frost
<!-- end-shortlog -->

(All contributors are identifiable with email addresses in the git version
Expand Down
47 changes: 42 additions & 5 deletions cylc/uiserver/graphql/tornado_ws.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,15 @@
GQL_COMPLETE = "complete" # Server -> Client
GQL_STOP = "stop" # Client -> Server

REQ_HEADER_INFO = {
'Host',
'User-Agent',
'Origin',
'Connection',
'Sec-Websocket-Version',
'Sec-Websocket-Protocol',
}


class ConnectionClosedException(Exception):
pass
Expand Down Expand Up @@ -106,7 +115,9 @@ def closed(self):
return self.ws.close_code is not None

async def close(self, code):
await self.ws.close(code)
ws_close = self.ws.close(code)
if ws_close is not None:
await ws_close

def remember_task(self, task):
self.pending_tasks.add(task)
Expand Down Expand Up @@ -325,15 +336,40 @@ async def on_start(self, connection_context, op_id, params):
finally:
if iterator:
await iterator.aclose()
await self.send_message(connection_context, op_id, GQL_COMPLETE)
with suppress(WebSocketClosedError):
await self.send_message(connection_context, op_id, GQL_COMPLETE)
await connection_context.unsubscribe(op_id)
await self.on_operation_complete(connection_context, op_id)

async def send_message(
self, connection_context, op_id=None, op_type=None, payload=None
):
message = self.build_message(op_id, op_type, payload)
return await connection_context.send(message)
try:
return await connection_context.send(message)
except WebSocketClosedError:
resolvers = connection_context.request_context.get('resolvers')
if resolvers is not None:
request = connection_context.request_context.get('request')
headers = {}
headers.update(getattr(request, 'headers', {}))
resolvers.log.warning(
'[GraphQL WS] Websocket closed on send'
f' (Op.Type: {op_type}, Op.ID: {op_id})'
f' to remote IP: {request.remote_ip}'
)
headers_string = ''
for key, val in headers.items():
if key in REQ_HEADER_INFO:
headers_string += f' {key}: {val} \n'
resolvers.log.debug(
'Websocket closed on send, with request context: \n'
f' Remote IP: {request.remote_ip} \n'
' Request Header Info: \n'
f'{headers_string}'
)
# Raise exception, in order to exit the on_start subscription loop.
raise

def build_message(self, _id, op_type, payload):
message = {}
Expand Down Expand Up @@ -381,8 +417,9 @@ async def send_error(

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

return await self.send_message(
connection_context, op_id, error_type, error_payload)
with suppress(WebSocketClosedError):
return await self.send_message(
connection_context, op_id, error_type, error_payload)

async def on_message(self, connection_context, message):
try:
Expand Down
2 changes: 2 additions & 0 deletions cylc/uiserver/resolvers.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
from cylc.flow.id import Tokens
from cylc.flow.network.resolvers import BaseResolvers
from cylc.flow.scripts.clean import CleanOptions, run
from cylc.flow.util import natural_sort_key

if TYPE_CHECKING:
from concurrent.futures import Executor
Expand Down Expand Up @@ -506,6 +507,7 @@ async def cat_log_files(cls, id_: Tokens, log: 'Logger') -> List[str]:
# this means that the most recent log file rotations
# will be at the top of the list
out.decode().splitlines(),
key=natural_sort_key,
reverse=True,
)
return []
Expand Down
35 changes: 0 additions & 35 deletions cylc/uiserver/ui/2.8.0/assets/Dashboard-iZtRnvU3.js

This file was deleted.

122 changes: 0 additions & 122 deletions cylc/uiserver/ui/2.8.0/assets/Graph-DjGaoGFs.js

This file was deleted.

1 change: 0 additions & 1 deletion cylc/uiserver/ui/2.8.0/assets/Guide-Dm6HFD0j.js

This file was deleted.

Loading
Loading