I have the following code which streams a video file from disk. [Test the code with the python asyncio module in the terminal]
python -m asyncio
from starlette.applications import Starlette
from starlette.responses import StreamingResponse
from starlette.routing import Route
import uvicorn
import random
import asyncio
video = open("C:\\Users\\USERNAME\\Downloads\\Big Buck Bunny\\Big Buck Bunny.mp4", 'rb')
async def stream_generator():
while True:
yield video.read(16384)
async def homepage(request):
return StreamingResponse(stream_generator(), media_type='video/mp4')
app = Starlette(debug=True, routes=[
Route('/', homepage),
])
if __name__ == "__main__":
config = uvicorn.Config(app)
server = uvicorn.Server(config)
await server.serve()
The problem arises when I need to use asyncio.sleep() statements in the stream_generator function. Currently I use asyncio.sleep() as an async no_op function. However, for some reason, the asyncio.sleep statements get cancelled when running with uvicorn and starlette.
I am not sure what's causing this but I am positive that this is happening because of either uvicorn or starlette because my app works when I simply print the bytes yielded by stream_generator.
The following code uses asyncio.sleep() in the stream_generator. Notice how it fails to stream the video to the web browser while continuously catching asyncio.CancelledError:
video = open("C:\\Users\\USERNAME\\Downloads\\Big Buck Bunny\\Big Buck Bunny.mp4", 'rb')
async def stream_generator():
while True:
try:
if random.random() * 100 > 99:
await asyncio.sleep(4)
except asyncio.CancelledError:
print("Caught the Culpritttttttttttttttttttttttttttt")
yield video.read(16384)
async def homepage(request):
# return JSONResponse({'1': '1'}
return StreamingResponse(stream_generator(), media_type='video/mp4')
app = Starlette(debug=True, routes=[
Route('/', homepage),
])