I've got a component of a larger Flask RESTful API who's purpose is to take a very large file (several GB, specifically an OVA virtualization image file) as a POST body, and then save it to a block device directly (treated as just a normal file in my code).
The issue I'm having is twofold:
(1) During the upload, before the save() call is made, Flask is writing the file out to a temporary file. This is blocking, and during the time this save takes (up to many minutes for a very large file on a slower connection), the entire API is blocked; other requests to the API must wait for the upload to complete.
(2) I've tried working around this by deferring the initial save and using a custom stream_factory to parse_form_data which writes directly to the destination, instead of using the standard Flask RESTful parsing and then calling save(). This avoids writing to a temporary file (which in my case is a double-write and takes up a lot of temp space), but the blocking behaviour is the same, just happening a bit later in my code path.
Things I've tried:
- I've tried both a standard
save()as well as a customparse_form_dataas detailed above. No effect. - I've tried both the default Flask
run()withthreaded=Trueand withoutthreaded=True. No effect. - I've tried both PyWSGI in addition to the default Flask
run(). No effect. - With PyWSHI, I've tried both
monkey.patch_all()and not. No effect. - I've tried using
os.set_blockingto disable blocking with the customstream_factorymethod. No effect. - I've tried running the
parse_form_datain a thread, however since I mustjoin()this to avoid the rest of the code proceeding until the upload is done, this also has no effect.
The relevant code can be found in this particular commit to my project where I implemented the custom stream_factory workaround; note that I did this to try to stop the double-save, not to address this issue, but it shows the code paths around which I'm working.
This sort of has me stumped; I need to both support these large file uploads, but I cannot have the API block other requests while the upload happens. Is there any way to stop these large file uploads from blocking other requests to the API?
EDIT: I've found the solution is to just use the Flask "debug" server for my API. It works properly here with threading=True and no moneypatch business, while Gevent/PyWSGI doesn't, and in my usecase the "debug" server is more than functional enough. Consider this closed without coming up with an explanation or "proper" solution.