-
Notifications
You must be signed in to change notification settings - Fork 218
Send websocket payload using a queue #633
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Conversation
It looks like it needs a pass with |
My project which uses |
Just leaving a note that I saw this happen before too. I recall it required many requests to be made in a very short period, and only occurred with specific setup of IO (which could be that it was just making it fast enough to allow this issue to occur). I wonder if there is a way to reliably reproduce this issue and add a test which would confirm that this patch solves it. |
I am working on a test for this. For now this patch does not work on Python 3.9, it prevents the server from starting up at all in websocket mode:
|
So I have a test on krassowski#1 which fails when |
The following diff makes this PR run fine for me: diff --git a/pylsp/python_lsp.py b/pylsp/python_lsp.py
index 2826ea1..e2f98c4 100644
--- a/pylsp/python_lsp.py
+++ b/pylsp/python_lsp.py
@@ -117,7 +117,8 @@ def start_ws_lang_server(port, check_parent_process, handler_class) -> None:
) from e
with ThreadPoolExecutor(max_workers=10) as tpool:
- send_queue = asyncio.Queue()
+ send_queue = None
+ loop = None
async def pylsp_ws(websocket):
log.debug("Creating LSP object")
@@ -147,11 +148,15 @@ def start_ws_lang_server(port, check_parent_process, handler_class) -> None:
"""Handler to send responses of processed requests to respective web socket clients"""
try:
payload = json.dumps(message, ensure_ascii=False)
- asyncio.run(send_queue.put((payload, websocket)))
+ loop.call_soon_threadsafe(send_queue.put_nowait, (payload, websocket))
except Exception as e:
log.exception("Failed to write message %s, %s", message, str(e))
async def run_server():
+ nonlocal send_queue, loop
+ send_queue = asyncio.Queue()
+ loop = asyncio.get_running_loop()
+
async with websockets.serve(pylsp_ws, port=port):
while 1:
# Wait until payload is available for sending Still no luck in creating an isolated reproduction. Any ideas? |
I added a simple end-to-end test for websocket server running and returning replies to make sure we do not introduce the I was not able to create a test which would reproduce the malformed JSON issue, so this is not a test for the motivating problem, but the test that I added includes a best effort to simulate conditions which would usually lead to it, so potentially someone else could pick it up in another PR. I will now push the patch from #633 (comment) to fix the failing test. |
@Raekkeri @nneskildsf can you confirm that the patch after my changes still solves the issue for you? Was the original one running well for you (it was failing for me locally and on CI once end-to-end test was added)? |
Hi,
we experienced JSON responses from the websocket server being mixed up if the requests from client (code editor, Monaco in our case) are too frequent. The response payload was basically unparseable JSON, and it seemed like a mashed up content of multiple JSON responses. Handling the send operations one-by-one by using the
asyncio.Queue
seemed to fix the issue, so here is a suggestion to apply the same fix into the main codebase.