Video upload to my ExpressJS Railway app is suuuuper slow. If locally hosting server, super fast.
Hey there. I am a bit at a loss and admittedly a bit of a noob when it comes to file transfer things.
I have a NextJS front-end and ExpressJS backend. The backend uses Multer.
I want to upload a file (up to 300MB) to my backend but I find that a 150MB video takes 5-10 minutes to upload but my upload speed is 34Mbps, so it should take closer to 30seconds.
I do not really know where to start looking, as I understand the problem could be in a number of places. I would hugely appreciate the chance to speak to someone with more experience.
Thank you!
77 Replies
Project ID:
ea5d7e7c-c61f-4f66-bfec-a5ec324949a1
You might find these helpful:
- Is there any network speed cap in developer plan
- Get an error when uploading a large file through my app: rror: abortedat connResetException
- Image upload using Express
⚠️ experimental feature
ea5d7e7c-c61f-4f66-bfec-a5ec324949a1
interesting, I'll try to replicate this issue and get back to you
Thank you, really appreciate it
now what would you say your upload speed to railway tops out at?
I am not sure, how do I check this? Network tab?
I got my other upload speed from fast.com
check in your task manager when uploading a file to your endpoint
it will tell you the current upload speed
Apologies for noobiness. I'm on mac so do you mean checking something like utilities or is this a browser based task manager?
I'm checking Utils now and network activity, looking for the railway connection
yeah mac has an equivalent to windows task manager, same deal
Ok so data sent/sec sitting around 99KB
yeah no
that isnt right
This is while I'm uploading the video
it would take a lotttttt longer than 5-10 mins at 99kb/s
Yeah
Am I looking in the wrong place :p
youre looking at the wrong thing
just look at the global upload speed
I followed this btw:
"Click the "Network" tab in the Activity Monitor window to see your upload and download speeds. The red value next to "Data Sent/Sec" highlights your upload speed while the green value next to "Data Received/Sec" shows your download speed."
okay then nvm lol
super confused. I tried pinging my API endpoint but for some reason that isn't working.
damn bro tough times
send me the railway domain for your api?
do either of those work for you?
ping works fast
And from my app the api routes do work
I have to head off but will continue in a few hours
try uploading a file to
https://utilities.up.railway.app/upload
with postman.
send a POST request with a binary type body, it will then send back info about request like upload speed.
this endpoint is limited to file sizes under 200 megabytes and upload speeds are throttled at 50 megabits, but you mentioned a 150 megabyte file and 34 megabit upload speeds, so those limitations shouldn’t impose your test with that endpoint.Thanks @Brody! I am picking this back up today.
I will note here that you won’t get speeds anywhere close to localhost levels. When transferring files locally, the files will transfer at the max speed of your drive, which is much much much faster than anything happening over a network
Ok so it looks muuuch better...:
uploaded file size 117.29 Megabytes
server received file in 34.28 seconds
average upload speed 3.42 Megabytes/s or 27.37 Megabits/s
that seems about right for a single connection file upload when you said you have 34 Mbit upload speeds
so that proves it's not an issue with railway or your network, just a code issue
that endpoint you uploaded to streams the uploaded file directly to the disk on railway, so there's no limitation from writing to disk either
where are you storing your uploaded files?
I'm using this code to do the upload from my client:
where formData is a FormData instance that I populate beforehand with the file.
onUploadProgress is used to show a progress bar.
Then the server-side receives it with:
The storage at this point is just to disk and temporary.
The does some processing but actually responds with 200 before any intensive processing is done, including saving the video to an external file storage.
I really appreciate the help btw. This already helps a lot.
so uploaded file is saved to disk, server responds with 200, then your app does some processing and then sends the file off to an external storage?
Yep
and just the first step takes a long time, like you have dial up?
Yeah. I can see the upload starts immediately, as the progress bar inches forward straight away, but it goes super slow throughout
how does save_feedback_video save the file to disk? does it ever buffer into memory?
could i see the function?
also, have you tried uploading a file to your api with postman and not your frontend?
if not, please try
So for that I rely on multer. I am quite new to multer and my understanding is it deals with getting the file out of the form-data and saving it to a specified storage path.
route related code and multer:
save_feedback_video related code:
I haven't. I will need to play with some stuff to pass the auth/security checks if I send via postman
could you please attempt?
Sure, it might take a little while but I'll report back 🙂
Btw is it generally better to send via binary or form-data
?
my api accepts form data too, if you wanted to check for any speed differences.
do you send other data along side the file? if so, then you need formdata
I do send other data
then yeah you need a form
It seems to have taken far less time
It hits an error because I couldn't provide a good request, but I got far enough that the file will have been uploaded
Says 40s
same file that you tested my endpoint with?
Yep!
Slightly separate note, Is it possible to ssh into Railway deployments?
well 40 seconds isn't that far off from 34.28 with my api
it's not, why do you ask?
I wanted to double check the video file is properly deleted once it is processed
ah I see
Yeah so I guess we've narrowed the problem to the client-side js I have?
add another middleware at the end that checks for the file and logs results
yeah you're using axios, switch to the browser native fetch
you showed me the client side axios request, it would be super easy to swap that to fetch
also axios isn't that good tbh
personally Ive always had problems with axios
not this problem, but still
Ah yeah, nice!
Ok I'll try this and report back
sounds good
So I tried the native fetch and it didn't seem to help. I don't get the progress bar functionality so it's hard to tell if the upload starts, but from my side after waiting for a long time (>3 minutes) the upload still hasn't completed
I will try uploading to your endpoint from my client to see if that is also slow
Ok so hosting my client locally and pointing the file at your endpoint is also slow, so this must be a problem with my code
Sending to your endpoint is also slow using native fetch
but postman was fast, so it must be client side issue
I will try writing a file upload client in html/js and see how that goes
but it will be much later today
I might even see about adding a progress bar to it 😉
Thanks Brody. I tried a bunch of things today. I have tried uploading using both of these code snippets:
Attempt 1:
Attempt 2:
Both had exactly the same (slow) performance. It's so strange.
I am using NextJS 13.2.3 so I don't know if this version is causing some problem...
nah I wouldn't think that code would have anything to do with nextjs, since that code is just vanilla js that's ran by the browser
now you said you tried using fetch, but that example uses xmlhttprequest, and axios uses xmlhttprequest when running in the browser, so technically you didn't change much
ignore the progress bar thing for now and just try with fetch, don't try to implement everything, just test form file uploads with fetch, keep it simple
Ah I also used this code:
And the "Attempt 2" above used a simple form submit
Not sure what API the <form> uses though
what browser are you using
Brave, but I also tried Safari and also tried on my phone
I just updated to NextJS 13.3 for the sake of it, but not luck
Haha this is so weird
this is super weird
we will get to the bottom of it
I'm quite excited to find the reason, I hope it's something good
I bet it will be something stupid
Yup 😬
wonder what framework postman uses for requests, since postman is literally a browser window
So I asked ChatGPT :p
Postman is an Electron-based application, which means it is built on top of Chromium and Node.js. While it shares some similarities with a browser, Postman is specifically designed and optimized for working with APIs, unlike web browsers that cater to a wide range of use cases and prioritize security and user experience.
When making requests, Postman does not use the same APIs as web browsers, like fetch or XMLHttpRequest. Instead, it uses Node.js libraries to make HTTP requests, such as the built-in http and https modules, or third-party libraries like request (now deprecated) or axios.
Since Postman is built on top of Node.js and uses server-side libraries for making requests, it is not subject to the same security restrictions and limitations as web browsers. Additionally, Postman is specifically optimized for working with APIs, which means it may have a more efficient implementation for handling file uploads compared to general-purpose web browsers.
Although Postman runs in an Electron-based environment, which uses Chromium under the hood, it should not be considered equivalent to a regular web browser in terms of functionality and performance characteristics. The difference in upload speed you are experiencing between Postman and web browsers can be attributed to these differences in implementation and optimization for API-related tasks.
Not sure if it is hallucinating
nope that's all correct
it would make sense that api calls are being done from the nodejs side of the postman app and not client side that is still chromium
Wouldn't that mean the file would have to be sent the their back-end before being sent elsewhere?
I just created an index.html file on my computer and stuck in:
results were:
so no change
no because nodejs can just read the file off disk and stream it to the endpoint
Oh right. That's cool
I wanna get into tests myself, but I have a busy day ahead of me and won't be on the computer for a while
Thanks, I will be around till late today. Really appreciate your help mate 🙂
no problem!
Hey @Brody. Do you think you'd be able to do tests today?
I didn't have any luck during the rest of the day. I need to fix it somehow as the website is customer facing
I've just said this in another help thread but I'll just paste it here for you too.
I have been extremely busy with work around the house, just had a wind storm that ripped off a bunch of siding among others things around the house that need attention.
Oh man! That sucks! Very sorry to hear it. Hope it's not too much work to recover
not many pieces came off, it's just a type of siding that is a pain to put on
update, I have some good but mostly bad news.
the good: I now know the determining factor as to why uploading data to railway is slow. whenever uploads are done with http 2 theyre slow, but uploads done with http 1.1 are fast (by default postman uses http 1.1, and insomnia uses 2.0). this issue is solely with railway.
the bad: I don’t know why this is the case, and you cant change to http 1.1 because thats entirely up to the browser, and any modern browser will default to http 2.
Ill be talking to the team about this as soon as I can
Oooh very interesting. I would have never found that on my own - thank you very much 🙂
Is it reasonable to assume that some day the uploads will be faster without me needing to change my code?
I'd love to hear why this is happening when you all find the answer 👀
yes I can confidently say that the team wouldn't let an issue like this slide for very long once they find out, I'll update you when I have more information
can you see this thread? https://discord.com/channels/713503345364697088/1096840076396343297
Yeah I saw it quite late. Thanks a lot for putting it together