-
Couldn't load subscription status.
- Fork 9
Jupyter on the same server as FastAPI route #52
-
Hi! For shits & giggles, I'd like to have Jupyter running on the same server mounted to a FastAPI route. I got some of the way there following this thread. On launching both uvicorn and jupyter, localhost:8000/jupyter/ behaves like a regular jupyter notebook would: it asks for a token, accepts correct token, opens file browser, opens a new notebook, but running code cells doesn't work. 1+1 hangs forever, with endless loop in the logs.
Would you be so kind to provide a minimal working example?
Beta Was this translation helpful? Give feedback.
All reactions
Replies: 2 comments 3 replies
-
Hi @liquidcarbon, can you check if this works for you?
Two key points:
- The Jupyter server requires both HTTP and WebSocket connections. So you must proxy both.
- By default, the Jupyter server does not allow cross-origin requests. You either need to configure the Jupyter server to allow cross-origin requests or modify the
Originheader in the proxy (seeJupyterCrossHost).
from collections.abc import AsyncIterator, Generator from contextlib import asynccontextmanager from typing import Any import httpx from fastapi import FastAPI, Request, WebSocket from fastapi_proxy_lib.core.http import ReverseHttpProxy from fastapi_proxy_lib.core.websocket import ReverseWebSocketProxy from httpx import AsyncClient class JupyterCrossHost(httpx.Auth): # ref: <https://www.python-httpx.org/advanced/authentication/> def auth_flow(self, request: httpx.Request) -> Generator[httpx.Request, Any, None]: request.headers["Origin"] = str(request.url) yield request client = AsyncClient(auth=JupyterCrossHost()) # `localhost:8888` is my jupyter server ws_proxy = ReverseWebSocketProxy(client, base_url="ws://localhost:8888/") http_proxy = ReverseHttpProxy(client, base_url="http://localhost:8888/") @asynccontextmanager async def close_proxy_event(_: FastAPI) -> AsyncIterator[None]: """Close proxy.""" yield await ws_proxy.aclose() await http_proxy.aclose() app = FastAPI(lifespan=close_proxy_event) @app.websocket("/{path:path}") async def _(websocket: WebSocket, path: str = ""): return await ws_proxy.proxy(websocket=websocket, path=path) @app.get("/{path:path}") @app.post("/{path:path}") @app.put("/{path:path}") @app.delete("/{path:path}") @app.patch("/{path:path}") @app.head("/{path:path}") @app.options("/{path:path}") async def _(request: Request, path: str = ""): return await http_proxy.proxy(request=request, path=path)
Beta Was this translation helpful? Give feedback.
All reactions
-
👀 1
-
Thanks for your response! Need more help...
Here's my setup:
Dockerfile
FROM python:3.12-slim
COPY --from=ghcr.io/astral-sh/uv:latest /uv /bin/uv
RUN useradd -m -u 1000 user
ENV PATH="/home/user/.local/bin:$PATH"
ENV UV_SYSTEM_PYTHON=1
RUN uv pip install fastapi jupyter uvicorn[standard] fastapi-proxy-lib
COPY --chown=user . /app
USER user
WORKDIR /app
EXPOSE 7860
CMD jupyter notebook --no-browser --ip=0.0.0.0 --port=8888 \
--ServerApp.allow_origin=* --ServerApp.allow_remote_access=True & \
uvicorn app:app --host 0.0.0.0 --port 7860
app.py
from collections.abc import AsyncIterator, Generator from contextlib import asynccontextmanager from typing import Any import httpx from fastapi import FastAPI, Request, WebSocket from fastapi_proxy_lib.core.http import ReverseHttpProxy from fastapi_proxy_lib.core.websocket import ReverseWebSocketProxy from httpx import AsyncClient class JupyterCrossHost(httpx.Auth): def auth_flow(self, request: httpx.Request) -> Generator[httpx.Request, Any, None]: request.headers["Origin"] = str(request.url) yield request client = AsyncClient(auth=JupyterCrossHost()) jupyter_http_proxy = ReverseHttpProxy(client, base_url="http://0.0.0.0:8888/") jupyter_ws_proxy = ReverseWebSocketProxy(client, base_url="ws://0.0.0.0:8888/") jupyter_path = "/jupyter/{path:path}" @asynccontextmanager async def close_proxy_event(_: FastAPI) -> AsyncIterator[None]: """Close proxy.""" yield await jupyter_ws_proxy.aclose() await jupyter_http_proxy.aclose() app = FastAPI(lifespan=close_proxy_event) @app.websocket(jupyter_path) async def _(websocket: WebSocket, path: str = ""): return await jupyter_ws_proxy.proxy(websocket=websocket, path=path) @app.get(jupyter_path) @app.post(jupyter_path) @app.put(jupyter_path) @app.delete(jupyter_path) @app.patch(jupyter_path) @app.head(jupyter_path) @app.options(jupyter_path) async def _(request: Request, path: str = ""): return await jupyter_http_proxy.proxy(request=request, path=path)
On launch:
Error in ReverseHttpProxy().proxy():
url: http://0.0.0.0:8888/api/sessions
request headers: Headers({'host': 'localhost:7860', 'user-agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:133.0) Gecko/20100101 Firefox/133.0', 'accept': '*/*', 'accept-language': 'en-US,en;q=0.5', 'accept-encoding': 'gzip, deflate, br, zstd', 'referer': 'http://localhost:7860/jupyter/jupyter/tree', 'authorization': 'token 83863f145fe61a1bf4450535a4d1204efbd97336eaaa681e', 'x-xsrftoken': '2|16169370|03b4de4a78a23e2a2fa2bca59120762d|1737652476', 'content-type': 'application/json', 'connection': 'keep-alive', 'cookie': '_xsrf=2|16169370|03b4de4a78a23e2a2fa2bca59120762d|1737652476; username-localhost-7860="2|1:0|10:1737606633|23:username-localhost-7860|200:eyJ1c2VybmFtZSI6ICJiZmNjMGU0MDRjNjc0YjllYTQ3ZTJmMzg5YTIxNmIzZSIsICJuYW1lIjogIkFub255bW91cyBWYWxldHVkbyIsICJkaXNwbGF5X25hbWUiOiAiQW5vbnltb3VzIFZhbGV0dWRvIiwgImluaXRpYWxzIjogIkFWIiwgImNvbG9yIjogbnVsbH0=|270e1afc18ad4b2b82008fd3bedd14b10118d1d2ce21ac054241add14506c368"; username-0-0-0-0-8888="2|1:0|10:1737653685|21:username-0-0-0-0-8888|196:eyJ1c2VybmFtZSI6ICIxZGRmZWE4ZjQxNDc0MWE4ODRjM2Q4MjJkNzNlODUzNCIsICJuYW1lIjogIkFub255bW91cyBUaHlvbmUiLCAiZGlzcGxheV9uYW1lIjogIkFub255bW91cyBUaHlvbmUiLCAiaW5pdGlhbHMiOiAiQVQiLCAiY29sb3IiOiBudWxsfQ==|b0b73fb3e7f87a715ca3f0a680388758faca940948063c8ae7487923fd1ab161"; _ga_R1FN4KJKJH=GS1.1.1714184238.4.1.1714185852.0.0.0; _ga=GA1.1.368724536.1713990148', 'sec-fetch-dest': 'empty', 'sec-fetch-mode': 'cors', 'sec-fetch-site': 'same-origin', 'priority': 'u=4', 'pragma': 'no-cache', 'cache-control': 'no-cache'})
on going to localhost:7860
httpx.ConnectError: All connection attempts failed
INFO: 172.17.0.1:43770 - "GET /jupyter/ HTTP/1.1" 502 Bad Gateway
What partially worked before:
from fastapi import FastAPI, Request, WebSocket
from starlette.responses import StreamingResponse
from starlette.websockets import WebSocketDisconnect
import httpx
import asyncio
app = FastAPI()
JUPYTER_URL = "http://0.0.0.0:8888"
@app.middleware("http")
async def proxy_middleware(request: Request, call_next):
async with httpx.AsyncClient(follow_redirects=True) as client:
# Forward the request to the Jupyter server
response = await client.request(
method=request.method,
url=f"{JUPYTER_URL}{request.url.path}?{request.url.query}",
headers=request.headers,
data=await request.body()
)
# Create a StreamingResponse to stream the content back to the client
async def stream_response():
async for chunk in response.aiter_bytes():
yield chunk
return StreamingResponse(
stream_response(),
status_code=response.status_code,
headers=response.headers
)
@app.websocket("/{path:path}")
async def websocket_endpoint(websocket: WebSocket, path: str):
await websocket.accept()
async with httpx.AsyncClient() as client:
async with client.stream("GET", f"{JUPYTER_URL}/{path}") as response:
async for chunk in response.aiter_bytes():
await websocket.send_bytes(chunk)
try:
while True:
data = await websocket.receive_text()
async with httpx.AsyncClient() as client:
await client.post(f"{JUPYTER_URL}/{path}", content=data)
except WebSocketDisconnect:
print("Client disconnected")
Beta Was this translation helpful? Give feedback.
All reactions
-
from collections.abc import AsyncIterator from contextlib import asynccontextmanager from fastapi import FastAPI, Request, WebSocket from fastapi_proxy_lib.core.http import ReverseHttpProxy from fastapi_proxy_lib.core.websocket import ReverseWebSocketProxy from httpx import AsyncClient client = AsyncClient() prefix = "/jupyter/" jupyter_http_proxy = ReverseHttpProxy(client, base_url=f"http://127.0.0.1:8888{prefix}") jupyter_ws_proxy = ReverseWebSocketProxy(client, base_url=f"ws://127.0.0.1:8888{prefix}") jupyter_path = f"{prefix}{{path:path}}" @asynccontextmanager async def close_proxy_event(_: FastAPI) -> AsyncIterator[None]: """Close proxy.""" yield await jupyter_ws_proxy.aclose() await jupyter_http_proxy.aclose() app = FastAPI(lifespan=close_proxy_event) @app.websocket(jupyter_path) async def _(websocket: WebSocket, path: str = ""): return await jupyter_ws_proxy.proxy(websocket=websocket, path=path) @app.get(jupyter_path) @app.post(jupyter_path) @app.put(jupyter_path) @app.delete(jupyter_path) @app.patch(jupyter_path) @app.head(jupyter_path) @app.options(jupyter_path) async def _(request: Request, path: str = ""): return await jupyter_http_proxy.proxy(request=request, path=path)
- I see that you allowed cross-origin requests with
--ServerApp.allow_origin=*(It's better not to use the wildcard*, specify it as your proxy server address instead), so you no longer needJupyterCrossHost. - You want a
/jupyter/prefix, but Jupyter doesn't know this and thinks it's still at the root path. So you need to use--ServerApp.base_url="/jupyter"to tell it to run at0.0.0.0:8888/jupyter/. Ref: https://discourse.jupyter.org/t/trouble-reverse-proxying-to-jupyterhub-on-a-subpath/13146/13. - Accordingly, the proxy's
base_urlalso needs to include/jupyter/prefix. - The proxy's
base_urlcannot be set to0.0.0.0, as this is not a valid address that your computer can access (it just means to listen on all addresses). You should set it to127.0.0.1orlocalhost.
Beta Was this translation helpful? Give feedback.
All reactions
-
Thank you for the code and explanations. It works, so far can't tell the difference in performance or otherwise from regular jupyter!
It's throwing some tornado websocket errors - do you happen to know why?
$ docker run -it -p 7860:7860 fastjupyter
INFO: Started server process [8]
INFO: Waiting for application startup.
INFO: Application startup complete.
INFO: Uvicorn running on http://0.0.0.0:7860 (Press CTRL+C to quit)
[I 2025年01月25日 02:38:48.980 ServerApp] jupyter_lsp | extension was successfully linked.
[I 2025年01月25日 02:38:48.982 ServerApp] jupyter_server_terminals | extension was successfully linked.
[I 2025年01月25日 02:38:48.986 ServerApp] jupyterlab | extension was successfully linked.
[I 2025年01月25日 02:38:48.989 ServerApp] notebook | extension was successfully linked.
[I 2025年01月25日 02:38:48.990 ServerApp] Writing Jupyter server cookie secret to /home/user/.local/share/jupyter/runtime/jupyter_cookie_secret
[I 2025年01月25日 02:38:49.654 ServerApp] notebook_shim | extension was successfully linked.
[I 2025年01月25日 02:38:49.681 ServerApp] notebook_shim | extension was successfully loaded.
[I 2025年01月25日 02:38:49.683 ServerApp] jupyter_lsp | extension was successfully loaded.
[I 2025年01月25日 02:38:49.684 ServerApp] jupyter_server_terminals | extension was successfully loaded.
[I 2025年01月25日 02:38:49.685 LabApp] JupyterLab extension loaded from /usr/local/lib/python3.12/site-packages/jupyterlab
[I 2025年01月25日 02:38:49.685 LabApp] JupyterLab application directory is /usr/local/share/jupyter/lab
[I 2025年01月25日 02:38:49.685 LabApp] Extension Manager is 'pypi'.
[I 2025年01月25日 02:38:49.807 ServerApp] jupyterlab | extension was successfully loaded.
[I 2025年01月25日 02:38:49.810 ServerApp] notebook | extension was successfully loaded.
[I 2025年01月25日 02:38:49.811 ServerApp] Serving notebooks from local directory: /app
[I 2025年01月25日 02:38:49.811 ServerApp] Jupyter Server 2.15.0 is running at:
[I 2025年01月25日 02:38:49.811 ServerApp] http://e4dd3151f087:8888/jupyter/tree?token=fefd052f7a602445ce2d8d003c86bac22cefd686e94a926c
[I 2025年01月25日 02:38:49.811 ServerApp] http://127.0.0.1:8888/jupyter/tree?token=fefd052f7a602445ce2d8d003c86bac22cefd686e94a926c
[I 2025年01月25日 02:38:49.811 ServerApp] Use Control-C to stop this server and shut down all kernels (twice to skip confirmation).
[C 2025年01月25日 02:38:49.813 ServerApp]
To access the server, open this file in a browser:
file:///home/user/.local/share/jupyter/runtime/jpserver-7-open.html
Or copy and paste one of these URLs:
http://e4dd3151f087:8888/jupyter/tree?token=fefd052f7a602445ce2d8d003c86bac22cefd686e94a926c
http://127.0.0.1:8888/jupyter/tree?token=fefd052f7a602445ce2d8d003c86bac22cefd686e94a926c
[I 2025年01月25日 02:38:49.830 ServerApp] Skipped non-installed server(s): bash-language-server, dockerfile-language-server-nodejs, javascript-typescript-langserver, jedi-language-server, julia-language-server, pyright, python-language-server, python-lsp-server, r-languageserver, sql-language-server, texlab, typescript-language-server, unified-language-server, vscode-css-languageserver-bin, vscode-html-languageserver-bin, vscode-json-languageserver-bin, yaml-language-server
INFO: 172.17.0.1:34972 - "GET / HTTP/1.1" 404 Not Found
[I 2025年01月25日 02:39:07.632 ServerApp] 302 GET /jupyter/ (@127.0.0.1) 0.41ms
INFO: 172.17.0.1:59418 - "GET /jupyter/ HTTP/1.1" 302 Found
[I 2025年01月25日 02:39:07.640 JupyterNotebookApp] 302 GET /jupyter/tree (@127.0.0.1) 0.94ms
INFO: 172.17.0.1:59418 - "GET /jupyter/tree HTTP/1.1" 302 Found
INFO: 172.17.0.1:59418 - "GET /jupyter/login?next=%2Fjupyter%2Ftree HTTP/1.1" 200 OK
[I 2025年01月25日 02:39:19.209 ServerApp] User f90d84d32f30445d9f413482596ae8c7 logged in.
[I 2025年01月25日 02:39:19.210 ServerApp] 302 POST /jupyter/login?next=%2Fjupyter%2Ftree (f90d84d32f30445d9f413482596ae8c7@127.0.0.1) 2.46ms
INFO: 172.17.0.1:42042 - "POST /jupyter/login?next=%2Fjupyter%2Ftree HTTP/1.1" 302 Found
INFO: 172.17.0.1:42042 - "GET /jupyter/tree HTTP/1.1" 200 OK
INFO: 172.17.0.1:42042 - "GET /jupyter/custom/custom.css HTTP/1.1" 200 OK
INFO: 172.17.0.1:42042 - "GET /jupyter/lab/extensions/jupyterlab_pygments/static/remoteEntry.5cbb9d2323598fbda535.js HTTP/1.1" 200 OK
INFO: 172.17.0.1:42042 - "GET /jupyter/lab/extensions/%40jupyter-widgets/jupyterlab-manager/static/remoteEntry.e4ff09401a2f575928c0.js HTTP/1.1" 200 OK
INFO: 172.17.0.1:42074 - "GET /jupyter/lab/extensions/%40jupyter-notebook/lab-extension/static/remoteEntry.cad89c571bc2aee4aff2.js HTTP/1.1" 200 OK
INFO: 172.17.0.1:42074 - "GET /jupyter/lab/extensions/jupyterlab_pygments/static/568.1e2faa2ba0bbe59c4780.js?v=1e2faa2ba0bbe59c4780 HTTP/1.1" 200 OK
INFO: 172.17.0.1:42042 - "GET /jupyter/lab/extensions/jupyterlab_pygments/static/747.67662283a5707eeb4d4c.js?v=67662283a5707eeb4d4c HTTP/1.1" 200 OK
INFO: 172.17.0.1:42074 - "GET /jupyter/lab/extensions/%40jupyter-widgets/jupyterlab-manager/static/898.4051a8b212a0f4c89d60.js?v=4051a8b212a0f4c89d60 HTTP/1.1" 200 OK
INFO: 172.17.0.1:42094 - "GET /jupyter/lab/extensions/%40jupyter-widgets/jupyterlab-manager/static/647.f4f9578285e357c95be3.js?v=f4f9578285e357c95be3 HTTP/1.1" 200 OK
INFO: 172.17.0.1:42084 - "GET /jupyter/lab/extensions/%40jupyter-widgets/jupyterlab-manager/static/651.fe40a967a60b543cf15c.js?v=fe40a967a60b543cf15c HTTP/1.1" 200 OK
INFO: 172.17.0.1:42106 - "GET /jupyter/lab/extensions/%40jupyter-widgets/jupyterlab-manager/static/439.33696bc45fbd403becbb.js?v=33696bc45fbd403becbb HTTP/1.1" 200 OK
INFO: 172.17.0.1:42074 - "GET /jupyter/lab/extensions/%40jupyter-widgets/jupyterlab-manager/static/722.3fefeac9cae358348cbc.js?v=3fefeac9cae358348cbc HTTP/1.1" 200 OK
INFO: 172.17.0.1:42042 - "GET /jupyter/lab/extensions/%40jupyter-widgets/jupyterlab-manager/static/420.063e2ee9f71033206b1f.js?v=063e2ee9f71033206b1f HTTP/1.1" 200 OK
INFO: 172.17.0.1:42110 - "GET /jupyter/lab/extensions/%40jupyter-widgets/jupyterlab-manager/static/327.8166aeb81cf1531ca240.js?v=8166aeb81cf1531ca240 HTTP/1.1" 200 OK
INFO: 172.17.0.1:42094 - "GET /jupyter/lab/extensions/%40jupyter-widgets/jupyterlab-manager/static/446.bf169bd3821a9ba1aa62.js?v=bf169bd3821a9ba1aa62 HTTP/1.1" 200 OK
INFO: 172.17.0.1:42084 - "GET /jupyter/lab/extensions/%40jupyter-notebook/lab-extension/static/568.f1a870f262b5e8588c75.js?v=f1a870f262b5e8588c75 HTTP/1.1" 200 OK
INFO: 172.17.0.1:42106 - "GET /jupyter/lab/extensions/%40jupyter-notebook/lab-extension/static/93.c48a681bb3e8043bbbd7.js?v=c48a681bb3e8043bbbd7 HTTP/1.1" 200 OK
INFO: 172.17.0.1:42094 - "GET /jupyter/api/me?1737772759730 HTTP/1.1" 200 OK
INFO: 172.17.0.1:42106 - "GET /jupyter/api/kernelspecs?1737772759730 HTTP/1.1" 200 OK
INFO: ('172.17.0.1', 42120) - "WebSocket /jupyter/api/events/subscribe" [accepted]
INFO: connection open
INFO: 172.17.0.1:42084 - "GET /jupyter/lab/api/settings?1737772759733 HTTP/1.1" 200 OK
INFO: 172.17.0.1:42094 - "GET /jupyter/api/kernels?1737772759739 HTTP/1.1" 200 OK
INFO: 172.17.0.1:42074 - "GET /jupyter/api/sessions?1737772759740 HTTP/1.1" 200 OK
INFO: 172.17.0.1:42110 - "GET /jupyter/api/terminals?1737772759740 HTTP/1.1" 200 OK
INFO: 172.17.0.1:42106 - "GET /jupyter/api/me?1737772759742 HTTP/1.1" 200 OK
INFO: 172.17.0.1:42042 - "GET /jupyter/api/kernelspecs?1737772759752 HTTP/1.1" 200 OK
INFO: 172.17.0.1:42106 - "GET /jupyter/lab/api/translations/default?1737772759949 HTTP/1.1" 200 OK
INFO: 172.17.0.1:42106 - "GET /jupyter/lsp/status?1737772760042 HTTP/1.1" 200 OK
INFO: 172.17.0.1:42094 - "GET /jupyter/lab/api/settings?ids_only=true&1737772760169 HTTP/1.1" 200 OK
INFO: 172.17.0.1:42074 - "GET /jupyter/lab/api/settings?1737772760169 HTTP/1.1" 200 OK
INFO: 172.17.0.1:42106 - "GET /jupyter/lab/api/translations?1737772760144 HTTP/1.1" 200 OK
INFO: 172.17.0.1:42094 - "GET /jupyter/lab/api/settings/%40jupyterlab/codemirror-extension%3Aplugin?1737772760267 HTTP/1.1" 200 OK
INFO: 172.17.0.1:42110 - "GET /jupyter/lab/api/themes/%40jupyterlab/theme-light-extension/index.css HTTP/1.1" 200 OK
INFO: 172.17.0.1:42084 - "GET /jupyter/api/contents?content=1&hash=0&1737772760149 HTTP/1.1" 200 OK
INFO: 172.17.0.1:42106 - "GET /jupyter/lab/api/settings/%40jupyterlab/notebook-extension%3Apanel?1737772760268 HTTP/1.1" 200 OK
INFO: 172.17.0.1:42074 - "GET /jupyter/lab/api/settings/%40jupyterlab/application-extension%3Acontext-menu?1737772760270 HTTP/1.1" 200 OK
INFO: 172.17.0.1:42110 - "GET /jupyter/lab/api/settings/%40jupyterlab/tooltip-extension%3Aconsoles?1737772760303 HTTP/1.1" 200 OK
INFO: 172.17.0.1:42094 - "GET /jupyter/lab/api/settings/%40jupyterlab/tooltip-extension%3Anotebooks?1737772760302 HTTP/1.1" 200 OK
INFO: 172.17.0.1:42084 - "GET /jupyter/lab/api/settings/%40jupyterlab/notebook-extension%3Atools?1737772760304 HTTP/1.1" 200 OK
INFO: 172.17.0.1:42042 - "GET /jupyter/lab/api/settings/%40jupyterlab/toc-extension%3Aregistry?1737772760304 HTTP/1.1" 200 OK
INFO: 172.17.0.1:42106 - "GET /jupyter/lab/api/settings/%40jupyterlab/notebook-extension%3Acompleter?1737772760305 HTTP/1.1" 200 OK
INFO: 172.17.0.1:42084 - "GET /jupyter/lab/api/settings/%40jupyterlab/debugger-extension%3Amain?1737772760306 HTTP/1.1" 200 OK
INFO: 172.17.0.1:42042 - "GET /jupyter/lab/api/settings/%40jupyterlab/celltags-extension%3Aplugin?1737772760306 HTTP/1.1" 200 OK
INFO: 172.17.0.1:42074 - "GET /jupyter/lab/api/settings/%40jupyterlab/metadataform-extension%3Ametadataforms?1737772760305 HTTP/1.1" 200 OK
INFO: 172.17.0.1:42110 - "GET /jupyter/lab/api/settings/%40jupyterlab/markdownviewer-extension%3Aplugin?1737772760305 HTTP/1.1" 200 OK
INFO: 172.17.0.1:42094 - "GET /jupyter/lab/api/settings/%40jupyterlab/fileeditor-extension%3Acompleter?1737772760306 HTTP/1.1" 200 OK
INFO: 172.17.0.1:42106 - "GET /jupyter/lab/api/settings/%40jupyterlab/cell-toolbar-extension%3Aplugin?1737772760306 HTTP/1.1" 200 OK
INFO: 172.17.0.1:42106 - "GET /jupyter/api/contents?content=1&hash=0&1737772760494 HTTP/1.1" 200 OK
[I 2025年01月25日 02:39:28.479 ServerApp] Creating new notebook in
[I 2025年01月25日 02:39:28.567 ServerApp] Writing notebook-signing key to /home/user/.local/share/jupyter/notebook_secret
INFO: 172.17.0.1:34952 - "POST /jupyter/api/contents?1737772768472 HTTP/1.1" 201 Created
INFO: 172.17.0.1:34952 - "GET /jupyter/api/contents/Untitled.ipynb?content=0&hash=0&1737772768601 HTTP/1.1" 200 OK
INFO: 172.17.0.1:34954 - "GET /jupyter/api/contents?content=1&hash=0&1737772768602 HTTP/1.1" 200 OK
INFO: 172.17.0.1:34952 - "GET /jupyter/api/contents/Untitled.ipynb?type=notebook&content=1&hash=1&1737772768666 HTTP/1.1" 200 OK
INFO: 172.17.0.1:34952 - "GET /jupyter/api/contents/Untitled.ipynb/checkpoints?1737772768934 HTTP/1.1" 200 OK
INFO: 172.17.0.1:34962 - "GET /jupyter/api/contents/Untitled.ipynb/checkpoints?1737772768935 HTTP/1.1" 200 OK
INFO: 172.17.0.1:34966 - "GET /jupyter/api/contents/Untitled.ipynb?content=0&hash=1&1737772768936 HTTP/1.1" 200 OK
INFO: 172.17.0.1:34972 - "GET /jupyter/api/contents/Untitled.ipynb/checkpoints?1737772768935 HTTP/1.1" 200 OK
INFO: 172.17.0.1:34966 - "GET /jupyter/api/sessions?1737772768949 HTTP/1.1" 200 OK
[I 2025年01月25日 02:39:28.954 ServerApp] Saving file at /Untitled.ipynb
INFO: 172.17.0.1:34962 - "PUT /jupyter/api/contents/Untitled.ipynb?1737772768951 HTTP/1.1" 200 OK
[I 2025年01月25日 02:39:29.064 ServerApp] Kernel started: 0d93a86d-b375-4f6d-a2e4-3ae92caecbad
INFO: 172.17.0.1:34966 - "POST /jupyter/api/sessions?1737772768956 HTTP/1.1" 201 Created
INFO: 172.17.0.1:34962 - "GET /jupyter/api/contents/Untitled.ipynb?content=0&hash=1&1737772769059 HTTP/1.1" 200 OK
INFO: 172.17.0.1:34966 - "GET /jupyter/api/sessions?1737772769070 HTTP/1.1" 200 OK
INFO: 172.17.0.1:34962 - "GET /jupyter/api/contents/Untitled.ipynb/checkpoints?1737772769075 HTTP/1.1" 200 OK
INFO: 172.17.0.1:34972 - "GET /jupyter/api/contents?content=1&hash=0&1737772769059 HTTP/1.1" 200 OK
INFO: 172.17.0.1:34972 - "GET /jupyter/notebooks/Untitled.ipynb HTTP/1.1" 200 OK
INFO: 172.17.0.1:34966 - "PATCH /jupyter/api/sessions/f3448cae-0cb7-47e7-9e3e-81f7bd809f47?1737772769165 HTTP/1.1" 200 OK
INFO: 172.17.0.1:34962 - "GET /jupyter/api/kernels?1737772769183 HTTP/1.1" 200 OK
INFO: 172.17.0.1:34972 - "PATCH /jupyter/api/sessions/f3448cae-0cb7-47e7-9e3e-81f7bd809f47?1737772769204 HTTP/1.1" 200 OK
INFO: 172.17.0.1:34966 - "GET /jupyter/api/sessions?1737772769205 HTTP/1.1" 200 OK
INFO: 172.17.0.1:34962 - "GET /jupyter/custom/custom.css HTTP/1.1" 304 Not Modified
INFO: 172.17.0.1:34954 - "GET /jupyter/api/nbconvert?1737772768656 HTTP/1.1" 200 OK
INFO: 172.17.0.1:34972 - "GET /jupyter/lab/extensions/jupyterlab_pygments/static/remoteEntry.5cbb9d2323598fbda535.js HTTP/1.1" 304 Not Modified
INFO: 172.17.0.1:34966 - "GET /jupyter/lab/extensions/%40jupyter-notebook/lab-extension/static/remoteEntry.cad89c571bc2aee4aff2.js HTTP/1.1" 304 Not Modified
INFO: 172.17.0.1:34954 - "GET /jupyter/lab/extensions/%40jupyter-widgets/jupyterlab-manager/static/remoteEntry.e4ff09401a2f575928c0.js HTTP/1.1" 304 Not Modified
INFO: 172.17.0.1:34972 - "GET /jupyter/lab/extensions/jupyterlab_pygments/static/568.1e2faa2ba0bbe59c4780.js?v=1e2faa2ba0bbe59c4780 HTTP/1.1" 304 Not Modified
INFO: 172.17.0.1:34954 - "GET /jupyter/lab/extensions/jupyterlab_pygments/static/747.67662283a5707eeb4d4c.js?v=67662283a5707eeb4d4c HTTP/1.1" 304 Not Modified
INFO: 172.17.0.1:34966 - "GET /jupyter/lab/extensions/%40jupyter-widgets/jupyterlab-manager/static/898.4051a8b212a0f4c89d60.js?v=4051a8b212a0f4c89d60 HTTP/1.1" 304 Not Modified
INFO: 172.17.0.1:34972 - "GET /jupyter/lab/extensions/%40jupyter-widgets/jupyterlab-manager/static/651.fe40a967a60b543cf15c.js?v=fe40a967a60b543cf15c HTTP/1.1" 304 Not Modified
INFO: 172.17.0.1:34962 - "GET /jupyter/lab/extensions/%40jupyter-widgets/jupyterlab-manager/static/647.f4f9578285e357c95be3.js?v=f4f9578285e357c95be3 HTTP/1.1" 304 Not Modified
INFO: 172.17.0.1:34952 - "GET /jupyter/lab/extensions/%40jupyter-widgets/jupyterlab-manager/static/420.063e2ee9f71033206b1f.js?v=063e2ee9f71033206b1f HTTP/1.1" 304 Not Modified
INFO: 172.17.0.1:34954 - "GET /jupyter/lab/extensions/%40jupyter-widgets/jupyterlab-manager/static/439.33696bc45fbd403becbb.js?v=33696bc45fbd403becbb HTTP/1.1" 304 Not Modified
INFO: 172.17.0.1:34966 - "GET /jupyter/lab/extensions/%40jupyter-widgets/jupyterlab-manager/static/327.8166aeb81cf1531ca240.js?v=8166aeb81cf1531ca240 HTTP/1.1" 304 Not Modified
INFO: 172.17.0.1:34962 - "GET /jupyter/lab/extensions/%40jupyter-widgets/jupyterlab-manager/static/446.bf169bd3821a9ba1aa62.js?v=bf169bd3821a9ba1aa62 HTTP/1.1" 304 Not Modified
INFO: 172.17.0.1:34972 - "GET /jupyter/lab/extensions/%40jupyter-widgets/jupyterlab-manager/static/722.3fefeac9cae358348cbc.js?v=3fefeac9cae358348cbc HTTP/1.1" 304 Not Modified
INFO: 172.17.0.1:34954 - "GET /jupyter/lab/extensions/%40jupyter-notebook/lab-extension/static/93.c48a681bb3e8043bbbd7.js?v=c48a681bb3e8043bbbd7 HTTP/1.1" 304 Not Modified
INFO: 172.17.0.1:34952 - "GET /jupyter/lab/extensions/%40jupyter-notebook/lab-extension/static/568.f1a870f262b5e8588c75.js?v=f1a870f262b5e8588c75 HTTP/1.1" 304 Not Modified
INFO: 172.17.0.1:34972 - "GET /jupyter/api/kernelspecs?1737772769519 HTTP/1.1" 200 OK
INFO: 172.17.0.1:34954 - "GET /jupyter/api/me?1737772769519 HTTP/1.1" 200 OK
INFO: 172.17.0.1:34966 - "GET /jupyter/lab/api/settings?1737772769525 HTTP/1.1" 200 OK
INFO: 172.17.0.1:34972 - "GET /jupyter/api/kernels?1737772769531 HTTP/1.1" 200 OK
INFO: 172.17.0.1:34954 - "GET /jupyter/api/sessions?1737772769531 HTTP/1.1" 200 OK
INFO: 172.17.0.1:34952 - "GET /jupyter/api/kernelspecs?1737772769532 HTTP/1.1" 200 OK
INFO: 172.17.0.1:34962 - "GET /jupyter/api/terminals?1737772769531 HTTP/1.1" 200 OK
INFO: 172.17.0.1:34966 - "GET /jupyter/api/me?1737772769532 HTTP/1.1" 200 OK
INFO: 172.17.0.1:34966 - "GET /jupyter/lab/api/translations/default?1737772769696 HTTP/1.1" 200 OK
INFO: 172.17.0.1:34966 - "GET /jupyter/lsp/status?1737772769722 HTTP/1.1" 200 OK
INFO: 172.17.0.1:34966 - "GET /jupyter/lab/api/translations?1737772769818 HTTP/1.1" 200 OK
INFO: 172.17.0.1:34954 - "GET /jupyter/lab/api/settings?ids_only=true&1737772769929 HTTP/1.1" 200 OK
INFO: 172.17.0.1:34972 - "GET /jupyter/api/contents/Untitled.ipynb/checkpoints?1737772769929 HTTP/1.1" 200 OK
INFO: 172.17.0.1:34962 - "GET /jupyter/api/contents/Untitled.ipynb?type=notebook&content=1&hash=1&1737772769951 HTTP/1.1" 200 OK
INFO: 172.17.0.1:34954 - "GET /jupyter/lab/api/settings/%40jupyterlab/codemirror-extension%3Aplugin?1737772770000 HTTP/1.1" 200 OK
INFO: 172.17.0.1:34972 - "GET /jupyter/lab/api/themes/%40jupyterlab/theme-light-extension/index.css HTTP/1.1" 304 Not Modified
INFO: 172.17.0.1:34954 - "GET /jupyter/lab/api/settings/%40jupyterlab/notebook-extension%3Apanel?1737772770001 HTTP/1.1" 200 OK
INFO: 172.17.0.1:34952 - "GET /jupyter/api/contents/Untitled.ipynb/checkpoints?1737772770010 HTTP/1.1" 200 OK
INFO: 172.17.0.1:34954 - "GET /jupyter/api/contents/Untitled.ipynb/checkpoints?1737772770050 HTTP/1.1" 200 OK
INFO: 172.17.0.1:34972 - "GET /jupyter/api/contents/Untitled.ipynb/checkpoints?1737772770051 HTTP/1.1" 200 OK
INFO: 172.17.0.1:34952 - "GET /jupyter/api/contents/Untitled.ipynb/checkpoints?1737772770051 HTTP/1.1" 200 OK
INFO: 172.17.0.1:34962 - "GET /jupyter/api/contents?content=1&hash=0&1737772770002 HTTP/1.1" 200 OK
INFO: 172.17.0.1:34954 - "GET /jupyter/api/contents/Untitled.ipynb/checkpoints?1737772770056 HTTP/1.1" 200 OK
INFO: 172.17.0.1:34954 - "GET /jupyter/api/sessions?1737772770208 HTTP/1.1" 200 OK
INFO: 172.17.0.1:34954 - "GET /jupyter/api/kernelspecs?1737772770227 HTTP/1.1" 200 OK
INFO: 172.17.0.1:34966 - "GET /jupyter/api/nbconvert?1737772769908 HTTP/1.1" 200 OK
INFO: 172.17.0.1:34966 - "GET /jupyter/api/terminals?1737772770468 HTTP/1.1" 200 OK
[I 2025年01月25日 02:39:31.258 ServerApp] Connecting to kernel 0d93a86d-b375-4f6d-a2e4-3ae92caecbad.
INFO: ('172.17.0.1', 34984) - "WebSocket /jupyter/api/kernels/0d93a86d-b375-4f6d-a2e4-3ae92caecbad/channels?session_id=75224964-c85e-4dc5-af93-1d3f6e4f07a4" [accepted]
INFO: connection open
[I 2025年01月25日 02:39:31.273 ServerApp] Connecting to kernel 0d93a86d-b375-4f6d-a2e4-3ae92caecbad.
INFO: ('172.17.0.1', 58168) - "WebSocket /jupyter/api/kernels/0d93a86d-b375-4f6d-a2e4-3ae92caecbad/channels?session_id=8ba904f4-8403-45db-8659-d414df12ceda" [accepted]
INFO: connection open
[I 2025年01月25日 02:39:31.290 ServerApp] Connecting to kernel 0d93a86d-b375-4f6d-a2e4-3ae92caecbad.
INFO: ('172.17.0.1', 58184) - "WebSocket /jupyter/api/kernels/0d93a86d-b375-4f6d-a2e4-3ae92caecbad/channels?session_id=c15b8b3f-0507-4df4-9357-1dcdb7f65cbf" [accepted]
INFO: connection open
INFO: ('172.17.0.1', 58196) - "WebSocket /jupyter/api/events/subscribe" [accepted]
INFO: connection open
[I 2025年01月25日 02:39:31.337 ServerApp] Connecting to kernel 0d93a86d-b375-4f6d-a2e4-3ae92caecbad.
INFO: ('172.17.0.1', 58210) - "WebSocket /jupyter/api/kernels/0d93a86d-b375-4f6d-a2e4-3ae92caecbad/channels?session_id=8c38fbdd-5152-4664-8c40-039f707b0a85" [accepted]
INFO: connection open
INFO: connection closed
INFO: connection closed
Task exception was never retrieved
future: <Task finished name='Task-261' coro=<WebSocketProtocol13.write_message.<locals>.wrapper() done, defined at /usr/local/lib/python3.12/site-packages/tornado/websocket.py:1086> exception=WebSocketClosedError()>
Traceback (most recent call last):
File "/usr/local/lib/python3.12/site-packages/tornado/websocket.py", line 1088, in wrapper
await fut
tornado.iostream.StreamClosedError: Stream is closed
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/local/lib/python3.12/site-packages/tornado/websocket.py", line 1090, in wrapper
raise WebSocketClosedError()
tornado.websocket.WebSocketClosedError
[I 2025年01月25日 02:39:31.378 ServerApp] Connecting to kernel 0d93a86d-b375-4f6d-a2e4-3ae92caecbad.
INFO: ('172.17.0.1', 58212) - "WebSocket /jupyter/api/kernels/0d93a86d-b375-4f6d-a2e4-3ae92caecbad/channels?session_id=25c6da44-08f7-41a6-9885-3bb9939703a4" [accepted]
INFO: connection open
INFO: connection closed
INFO: 172.17.0.1:34966 - "GET /jupyter/api/sessions?1737772771433 HTTP/1.1" 200 OK
INFO: 172.17.0.1:34954 - "GET /jupyter/api/kernels?1737772771433 HTTP/1.1" 200 OK
INFO: 172.17.0.1:34966 - "GET /jupyter/api/sessions?1737772771508 HTTP/1.1" 200 OK
INFO: 172.17.0.1:34954 - "GET /jupyter/api/kernels?1737772771509 HTTP/1.1" 200 OK
INFO: 172.17.0.1:34954 - "GET /jupyter/static/favicons/favicon-busy-1.ico HTTP/1.1" 200 OK
INFO: 172.17.0.1:34954 - "GET /jupyter/api/contents/Untitled.ipynb/checkpoints?1737772772200 HTTP/1.1" 200 OK
Beta Was this translation helpful? Give feedback.
All reactions
-
IDK. But tornado is not a dependency of fastapi, uvicorn, or fastapi-proxy-lib, but rather a dependency of jupyter, so you might need to ask jupyter or tornado.
The only thing I can think of is that when the browser requests to close the websocket connection, fastapi-proxy-lib or its dependency httpx-ws did not properly complete the closing handshake with the proxied jupyter websocket connection.
My suggestion is "just let it go". If it is indeed due to the websocket closing handshake, then it has already closed anyway, so it should not affect the normal transmission of messages.
Beta Was this translation helpful? Give feedback.
All reactions
-
👍 1