Skip to content
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

Mounting app on different path does not seem to work #186

Closed
thondeboer opened this issue Dec 20, 2023 · 12 comments
Closed

Mounting app on different path does not seem to work #186

thondeboer opened this issue Dec 20, 2023 · 12 comments

Comments

@thondeboer
Copy link

Hi, loving the streamsync and somewhat worried that it has been quiet for a while on the release front here...hope you have not lost interest! This is my favorite webapp dev tool since it is sooo easy to get something working...Have also developed a couple of custom components...

anyhoo...

I am trying to mount an app under a different path and followed the directions on the custom server section of the docs, but I am getting a

SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data

In the browser and this in the logs:

ERROR:    Exception in ASGI application
Traceback (most recent call last):
  File "/home/tdeboer/.cache/pypoetry/virtualenvs/dash-bio-B22Gy4nA-py3.10/lib/python3.10/site-packages/uvicorn/protocols/http/h11_impl.py", line 408, in run_asgi
    result = await app(  # type: ignore[func-returns-value]
  File "/home/tdeboer/.cache/pypoetry/virtualenvs/dash-bio-B22Gy4nA-py3.10/lib/python3.10/site-packages/uvicorn/middleware/proxy_headers.py", line 84, in __call__
    return await self.app(scope, receive, send)
  File "/home/tdeboer/.cache/pypoetry/virtualenvs/dash-bio-B22Gy4nA-py3.10/lib/python3.10/site-packages/fastapi/applications.py", line 1106, in __call__
    await super().__call__(scope, receive, send)
  File "/home/tdeboer/.cache/pypoetry/virtualenvs/dash-bio-B22Gy4nA-py3.10/lib/python3.10/site-packages/starlette/applications.py", line 122, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/home/tdeboer/.cache/pypoetry/virtualenvs/dash-bio-B22Gy4nA-py3.10/lib/python3.10/site-packages/starlette/middleware/errors.py", line 184, in __call__
    raise exc
  File "/home/tdeboer/.cache/pypoetry/virtualenvs/dash-bio-B22Gy4nA-py3.10/lib/python3.10/site-packages/starlette/middleware/errors.py", line 162, in __call__
    await self.app(scope, receive, _send)
  File "/home/tdeboer/.cache/pypoetry/virtualenvs/dash-bio-B22Gy4nA-py3.10/lib/python3.10/site-packages/starlette/middleware/exceptions.py", line 79, in __call__
    raise exc
  File "/home/tdeboer/.cache/pypoetry/virtualenvs/dash-bio-B22Gy4nA-py3.10/lib/python3.10/site-packages/starlette/middleware/exceptions.py", line 68, in __call__
    await self.app(scope, receive, sender)
  File "/home/tdeboer/.cache/pypoetry/virtualenvs/dash-bio-B22Gy4nA-py3.10/lib/python3.10/site-packages/fastapi/middleware/asyncexitstack.py", line 20, in __call__
    raise e
  File "/home/tdeboer/.cache/pypoetry/virtualenvs/dash-bio-B22Gy4nA-py3.10/lib/python3.10/site-packages/fastapi/middleware/asyncexitstack.py", line 17, in __call__
    await self.app(scope, receive, send)
  File "/home/tdeboer/.cache/pypoetry/virtualenvs/dash-bio-B22Gy4nA-py3.10/lib/python3.10/site-packages/starlette/routing.py", line 718, in __call__
    await route.handle(scope, receive, send)
  File "/home/tdeboer/.cache/pypoetry/virtualenvs/dash-bio-B22Gy4nA-py3.10/lib/python3.10/site-packages/starlette/routing.py", line 443, in handle
    await self.app(scope, receive, send)
  File "/home/tdeboer/.cache/pypoetry/virtualenvs/dash-bio-B22Gy4nA-py3.10/lib/python3.10/site-packages/fastapi/applications.py", line 1106, in __call__
    await super().__call__(scope, receive, send)
  File "/home/tdeboer/.cache/pypoetry/virtualenvs/dash-bio-B22Gy4nA-py3.10/lib/python3.10/site-packages/starlette/applications.py", line 122, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/home/tdeboer/.cache/pypoetry/virtualenvs/dash-bio-B22Gy4nA-py3.10/lib/python3.10/site-packages/starlette/middleware/errors.py", line 184, in __call__
    raise exc
  File "/home/tdeboer/.cache/pypoetry/virtualenvs/dash-bio-B22Gy4nA-py3.10/lib/python3.10/site-packages/starlette/middleware/errors.py", line 162, in __call__
    await self.app(scope, receive, _send)
  File "/home/tdeboer/.cache/pypoetry/virtualenvs/dash-bio-B22Gy4nA-py3.10/lib/python3.10/site-packages/starlette/middleware/exceptions.py", line 79, in __call__
    raise exc
  File "/home/tdeboer/.cache/pypoetry/virtualenvs/dash-bio-B22Gy4nA-py3.10/lib/python3.10/site-packages/starlette/middleware/exceptions.py", line 68, in __call__
    await self.app(scope, receive, sender)
  File "/home/tdeboer/.cache/pypoetry/virtualenvs/dash-bio-B22Gy4nA-py3.10/lib/python3.10/site-packages/fastapi/middleware/asyncexitstack.py", line 20, in __call__
    raise e
  File "/home/tdeboer/.cache/pypoetry/virtualenvs/dash-bio-B22Gy4nA-py3.10/lib/python3.10/site-packages/fastapi/middleware/asyncexitstack.py", line 17, in __call__
    await self.app(scope, receive, send)
  File "/home/tdeboer/.cache/pypoetry/virtualenvs/dash-bio-B22Gy4nA-py3.10/lib/python3.10/site-packages/starlette/routing.py", line 718, in __call__
    await route.handle(scope, receive, send)
  File "/home/tdeboer/.cache/pypoetry/virtualenvs/dash-bio-B22Gy4nA-py3.10/lib/python3.10/site-packages/starlette/routing.py", line 276, in handle
    await self.app(scope, receive, send)
  File "/home/tdeboer/.cache/pypoetry/virtualenvs/dash-bio-B22Gy4nA-py3.10/lib/python3.10/site-packages/starlette/routing.py", line 66, in app
    response = await func(request)
  File "/home/tdeboer/.cache/pypoetry/virtualenvs/dash-bio-B22Gy4nA-py3.10/lib/python3.10/site-packages/fastapi/routing.py", line 274, in app
    raw_response = await run_endpoint_function(
  File "/home/tdeboer/.cache/pypoetry/virtualenvs/dash-bio-B22Gy4nA-py3.10/lib/python3.10/site-packages/fastapi/routing.py", line 191, in run_endpoint_function
    return await dependant.call(**values)
  File "/home/tdeboer/.cache/pypoetry/virtualenvs/dash-bio-B22Gy4nA-py3.10/lib/python3.10/site-packages/streamsync/serve.py", line 122, in init
    response = await app_runner.init_session(InitSessionRequestPayload(
  File "/home/tdeboer/.cache/pypoetry/virtualenvs/dash-bio-B22Gy4nA-py3.10/lib/python3.10/site-packages/streamsync/app_runner.py", line 668, in init_session
    return await self.dispatch_message(None, InitSessionRequest(
  File "/home/tdeboer/.cache/pypoetry/virtualenvs/dash-bio-B22Gy4nA-py3.10/lib/python3.10/site-packages/streamsync/app_runner.py", line 611, in dispatch_message
    raise ValueError(
ValueError: Cannot dispatch message. No connection to AppProcess server is set.

This is the (only slightly modified example) for server.py

import uvicorn
import streamsync.serve
from fastapi import FastAPI, Response

root_asgi_app = FastAPI()
sub_asgi_app_1 = streamsync.serve.get_asgi_app(".", "run")

root_asgi_app.mount("/hello", sub_asgi_app_1)

@root_asgi_app.get("/")
async def init():
    return Response("""
    <h1>Welcome to the App Hub</h1>
    """)

uvicorn.run(root_asgi_app,
    host="0.0.0.0",
    port=5328,
    log_level="warning",
    ws_max_size=streamsync.serve.MAX_WEBSOCKET_MESSAGE_SIZE)

I used the default app hello and placed the serve.py in the same directory and also tried different locations, but always the same result. THe fastAPI is running I am pretty sure, since I get the welcome message, but the path /hello gets the error.

Thanks again for this great app!

@FabienArcellier
Copy link
Collaborator

FabienArcellier commented Dec 20, 2023

I usually avoid using relative path in application. Did you try using module path as reference ?

import uvicorn
import streamsync.serve
from fastapi import FastAPI, Response
import os.path

app_dir = os.path.dirname(__file__)

root_asgi_app = FastAPI()
sub_asgi_app_1 = streamsync.serve.get_asgi_app(app_dir, "run")

root_asgi_app.mount("/hello", sub_asgi_app_1)

@root_asgi_app.get("/")
async def init():
    return Response("""
    <h1>Welcome to the App Hub</h1>
    """)

uvicorn.run(root_asgi_app,
    host="0.0.0.0",
    port=5328,
    log_level="warning",
    ws_max_size=streamsync.serve.MAX_WEBSOCKET_MESSAGE_SIZE)

@thondeboer
Copy link
Author

Are you saying that that works for you? I still get the same error....The relative path was taken from your example doc, so figured that that was OK to use..

@FabienArcellier
Copy link
Collaborator

My bad, I didn't test the correct behavior. I confirm it doesn't work. The problem is due to lifespan context that is not trigger when running sub application (at serve.py:async def lifespan(app: FastAPI)) : more info on fastapi documentation (https://fastapi.tiangolo.com/advanced/events/#sub-applications)

I have find a hack to make it work. I forward the lifespan from subapplication to main application root_asgi_app = FastAPI(lifespan=sub_asgi_app_1.router.lifespan_context). Could you tell me if it's working for you ?

You will rely on fastapi internal, I can't garantee it will work after update. We have to discuss with @ramedina86 on a change to expose lifespan properly to streamsync developper and update the documentation.

import uvicorn
import streamsync.serve
from fastapi import FastAPI, Response
import os.path

app_dir = os.path.dirname(__file__)

sub_asgi_app_1 = streamsync.serve.get_asgi_app(app_dir, "run")
root_asgi_app = FastAPI(lifespan=sub_asgi_app_1.router.lifespan_context)

root_asgi_app.mount("/hello", sub_asgi_app_1)

@root_asgi_app.get("/")
async def init():
    return Response("""
    <h1>Welcome to the App Hub</h1>
    """)

uvicorn.run(root_asgi_app,
    host="0.0.0.0",
    port=5328,
    log_level="warning",
    ws_max_size=streamsync.serve.MAX_WEBSOCKET_MESSAGE_SIZE)

@thondeboer
Copy link
Author

thondeboer commented Dec 21, 2023

This works great...Thanks! Now I have to figure out how to make this work with a reverse proxy, since I am having issues with NGINX, but that is likely separate issue.

@thondeboer
Copy link
Author

I am getting a "Connection rejected" error from streamsync when I put my app behind a reverse proxy, but only if I use the different mount point as we discussed above. When my app is just at the root, the authentication and app works fine, so we are still not out of the woods...Any ideas about this issue? Is this an nginx issue or still something with FastAPI?

@FabienArcellier
Copy link
Collaborator

FabienArcellier commented Dec 22, 2023

I have tried a configuration using nginx as reverse proxy. It is working fine for me.

image

here is the reverse proxy configuration I have used

nginx/conf.d/default.conf

server{
    listen 8080;
    location / {
        proxy_pass http://app:5328;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

docker-compose

version: "3.9"
services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
    volumes:
      - ./src/:/app/src
    init: true

  reverse_proxy:
    image: nginx:latest
    ports:
      - 8080:8080
    volumes:
      - ./nginx/conf.d:/etc/nginx/conf.d

Dockerfile

FROM python:3.10 as builder

RUN mkdir -p /app
WORKDIR /app
RUN pip3 install poetry

COPY . /app
RUN poetry install --without dev

FROM python:3.10-bullseye as base

COPY --from=builder /app /app

RUN groupadd --gid 1000 user && \
    useradd --create-home -u 1000 -g 1000 user && \
    chown -R user:user /app

USER user
WORKDIR /app

ENV PATH="/app/.venv/bin:$PATH"
CMD ["python", "src/app/webapp.py"]
#CMD ["streamsync","--host", "0.0.0.0", "--port", "5328", "edit", "src/app"]

@thondeboer
Copy link
Author

thondeboer commented Dec 22, 2023

the issue is when you mount the app on a different path...
/ works fine /hello does not (for me). I mean, i have the equivalent of

server{
    listen 8080;
    location /hello {
        proxy_pass http://app:5328;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

And use the mount trick you showed earlier...
I have multiple apps running on my nginx server, one under / which works fine, and the other I wanted to move to /hello and that gives me the issue...

I am running it on a https server with authentication.

I'll see if I can make a reproducible version of it, but since it requries certificates etc. and PAM authentication, not sure that it is easy...But I will start with the docker example you gave

@FabienArcellier
Copy link
Collaborator

Did you check if you have any info when you enable complete logging on nginx ? Could you share logs with us ? Could you also post a screenshot of the network section of your developer tools with the page that fails ?

image

@thondeboer
Copy link
Author

Thanks...I got it to work..It WAS an issue with my NGINX configuration, so all good now!

@ramedina86
Copy link
Collaborator

Hey @thondeboer apologies for being unresponsive and I'm very happy to hear you still like Streamsync. No need to worry about its future, though I appreciate the concern. In fact, I've been busy preparing for the next stage; I'll be working full time on this.

@thondeboer
Copy link
Author

thondeboer commented Jan 4, 2024 via email

@ramedina86
Copy link
Collaborator

@FabienArcellier thought the same and developed an extension mechanism which is very much in line with what you mentioned.

Here's the PR if you're curious #166

This is still being refined but coming rather soon.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants