Hi,
I am quite new to Dash.
I work on a Raspberry Pi cm5 running Trixie to develop a motion detection camera and also have the possibility of live streaming the camera data.
I use Dash 4.4.0 and Python 3.13.5. I also use Picamera2 with the CircularOutput2 feature. There is a PIR sensor generating an interrupt when detecting a movement which triggers the storing in a file of the video capturing the object that triggered the interrupt. This uses the CircularOutput2 feature of Picamera2.
There is a web app using Dash which can display the videos stored on the pi that were captured following a movement detection. The video is displayed in the webpage using DashPlayer.
In order to display the camera signal, an image of the camera is made available in jpeg format through a function using the yield capability of Python. This function uses the picamera2 function capture_file and is called every second (see code below).
def generate_frame():
while True:
stream = io.BytesIO()
picam2.capture_file(stream, format="jpeg")
jpeg_data = stream.getvalue()
yield (
b"--frame\r\n" + b"Content-Type: image/jpeg\r\n\r\n" + jpeg_data + b"\r\n"
)
time.sleep(1)
In the Dash app, the dash server calls the function above with the following combination of route and app_layout information:
@app.server.route("/video_feed)
def video_fedd():
return Response(
generate_frame(), mimetype="multipart/x-mixed-replace; boundary = frame"
)
In the app_layout:
html.Img(src="/video_feed", style={'width': '60%', 'border': '2px solid #333'})
The application was developed using the non production web server started in main with:
app.run(host='0.0.0.0',debug=False, port=10033)
Where app is the Dash app.
The application works fine.
I wanted to replace the non production server with gunicorn. I ended up using the following approach to run gunicorn:
class StandaloneApplication(gunicorn.app.base.BaseApplication):
def __init__(self, app, options=None):
self.options = options or {}
self.application = app
super().__init__()
def load_config(self):
config = {key: value for key, value in self.options.items()
if key in self.cfg.settings and value is not None}
for key, value in config.items():
self.cfg.set(key.lower(), value)
def load(self):
return self.application
if __name__=='__main__':
options = {
'bind': '%s:%s' % ('0.0.0.0', '10033'),
'workers': 2,
}
initialize()
StandaloneApplication(server, options).run()
When using gunicorn, the initalization works well. However, no image is ever displayed in the webpage and after a few seconds, the application crashes stating that a worker might have gone out of memory.
After some investigation, it seems the function call picam2.capture_file(stream, format=“jpeg”) hangs with the gunicorn setup when it does not with the non production server.I am not sure why. Could you suggest an approach to investigate this issue and/or explain why I have this issue?
Thank you,
JF