I’m deploying a web app where some livestream features are present. However, I’m encountering timeout issues when running the app on Koyeb even though it works on my local machine fine.
I did some research and saw that a vCPU is totally different than a CPU. My CPU is a AMD Ryzen 7 3700X 8-Core Processor. After doing the conversion to vCPU, I found this:
(16 Threads x 8 Cores) x 1 CPU = 128 vCPU
I checked in Koyeb plans tab but I wasn’t able to find an option that would allow me to run the app at 128 vCPU.
Can I get some help or insights please? Thanks!
Do the graphs indicate that the CPU is the bottleneck? Is it fully utilized? The problem might be somewhere else.
Are you getting HTTP timeouts?
A vCPU, is simply a virtualized CPU. I’m not sure why you multiplied the number of threads by the number of cores. A 2XLarge or 3XLarge will probably match the performance of your Ryzen 7 3700x.
Thanks for your reply!
I got the conversion from this website.
Here is the log of the error I’m getting:
10.250.0.20 - - [28/Jan/2025:05:47:42 +0000] "GET /video_feed HTTP/1.1" 500 0 "-" "-"
[2025-01-28 05:47:42 +0000] [1] [CRITICAL] WORKER TIMEOUT (pid:522)
[2025-01-28 05:47:42 +0000] [522] [ERROR] Error handling request /video_feed
Traceback (most recent call last):
File "/workspace/.heroku/python/lib/python3.12/site-packages/gunicorn/workers/sync.py", line 134, in handle
self.handle_request(listener, req, client, addr)
File "/workspace/.heroku/python/lib/python3.12/site-packages/gunicorn/workers/sync.py", line 177, in handle_request
respiter = self.wsgi(environ, resp.start_response)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/workspace/.heroku/python/lib/python3.12/site-packages/flask/app.py", line 2552, in __call__
return self.wsgi_app(environ, start_response)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/workspace/.heroku/python/lib/python3.12/site-packages/flask/app.py", line 2529, in wsgi_app
response = self.full_dispatch_request()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/workspace/.heroku/python/lib/python3.12/site-packages/flask/app.py", line 1823, in full_dispatch_request
rv = self.dispatch_request()
^^^^^^^^^^^^^^^^^^^^^^^
File "/workspace/.heroku/python/lib/python3.12/site-packages/flask/app.py", line 1799, in dispatch_request
return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/workspace/cleanapp.py", line 366, in video_feed
redirect(url_for('video_feed'))
^^^^^^^^^^^^^^^^^^^^^
File "/workspace/.heroku/python/lib/python3.12/site-packages/flask/helpers.py", line 256, in url_for
return current_app.url_for(
^^^^^^^^^^^^^^^^^^^^
File "/workspace/.heroku/python/lib/python3.12/site-packages/flask/app.py", line 2023, in url_for
rv = url_adapter.build( # type: ignore[union-attr]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/workspace/.heroku/python/lib/python3.12/site-packages/werkzeug/routing/map.py", line 922, in build
rv = self._partial_build(endpoint, values, method, append_unknown)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/workspace/.heroku/python/lib/python3.12/site-packages/werkzeug/routing/map.py", line 801, in _partial_build
rv = self._partial_build(
^^^^^^^^^^^^^^^^^^^^
File "/workspace/.heroku/python/lib/python3.12/site-packages/werkzeug/routing/map.py", line 813, in _partial_build
if rule.suitable_for(values, method):
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/workspace/.heroku/python/lib/python3.12/site-packages/werkzeug/routing/rules.py", line 869, in suitable_for
def suitable_for(
File "/workspace/.heroku/python/lib/python3.12/site-packages/gunicorn/workers/base.py", line 204, in handle_abort
sys.exit(1)
SystemExit: 1
Hi @Abdoulaye_Diallo,
It looks like your worker timeouts when handling /video_feed
path. Can you share the code of this function?
Maybe it does some long operations?
Indeed, according to ChatGPT, the function does some long operations. However, it works fine on all local machines I tested the app on. Here is the code for reference:
def imageflow_demo_yolo_UI_integrated(args):
print('real path', args.path, 'demo', args.demo)
if args.path.isdigit():
cap = cv2.VideoCapture(args.camid)
else:
cap = cv2.VideoCapture(args.path)
width = cap.get(cv2.CAP_PROP_FRAME_WIDTH) # float
height = cap.get(cv2.CAP_PROP_FRAME_HEIGHT) # float
fps = cap.get(cv2.CAP_PROP_FPS)
print('step1 ok')
if not os.path.exists(args.path):
print('path does not exist')
else:
print('victory')
if not cap.isOpened():
print('path exist but cannot be opened')
else:
print('victoryy')
print('about to start')
while True:
print('CV is reading')
ret_val, frame = cap.read()
if not ret_val:
print('restarting CV')
print('path', args.path, 'demo', args.demo)
if args.path.isdigit():
cap = cv2.VideoCapture(int(args.path))
else:
cap = cv2.VideoCapture(args.path)
width = cap.get(cv2.CAP_PROP_FRAME_WIDTH) # float
height = cap.get(cv2.CAP_PROP_FRAME_HEIGHT) # float
fps = cap.get(cv2.CAP_PROP_FPS)
print('unsucessful extraction of frame ... ')
if ret_val:
ret, buffer = cv2.imencode('.jpg', frame)
frame = buffer.tobytes()
print('successfully extracted frame ...')
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
video_source = None
lst_sources = {}
ind=0
current_time = None
@app.route('/video_feed')
def video_feed():
global video_source
global current_time
global ind
# Get the URL from the query parameters
video_source = request.args.get('url')
args = arti_parser(video_source).parse_args()
print('test', args.path, args.experiment_name)
# keep a list of all the new cameras added to the system
if args.path not in lst_sources:
lst_sources[args.path]=ind
ind+=1
print("passing with", args.path)
if not args.experiment_name:
args.experiment_name ="exp_name"
file_name = os.path.join("exp_dir", args.experiment_name)
os.makedirs(file_name, exist_ok=True)
logger.info("Args: {}".format(args))
logger.info("Model Summary: No CV model::reading frames")
print(args.path)
print('dartagnan')
# None is between quotes becasue of line 29. If str(None) is None in quotes
while args.path=='None':
redirect(url_for('video_feed'))
return Response(imageflow_demo_yolo_UI_integrated(args),
mimetype='multipart/x-mixed-replace; boundary=frame')
I think it should be if
instead of while
and you should return return redirect(url_for('video_feed'))
if args.path=='None':
return redirect(url_for('video_feed'))