Reputation: 13702
I've created a custom upload / serve mechanism to manage media files for a meteor app.
The whole application hangs after ~800 - 4000 (it varies from system to system) files are served to a browser
var idx = 0;
var send = Meteor.npmRequire('send');
WebApp.connectHandlers.use(function(req, res /*, next*/ ) {
sendFile(req, res, '/penken.jpg');
});
var sendFile = function(req, res, urlPath) {
var lidx = idx++;
console.log(lidx, 'requesting', urlPath);
send(req, urlPath, {
root: process.env.PWD + '/.uploads',
maxAge: 20 * 60 * 1000
}).pipe(res);
};
meteor
issue or it is a send
, WebApp
etc.Interestingly enough if I run wget 10000 times using the following bash line:
for i in `seq 10000`; do wget http://localhost:3000/uploads/penken.jpg -qO /dev/null; sleep 0.01; done
The issue doesn't manifest itself
Find it at: https://github.com/albertmatyi/meteor-hangs
git clone https://github.com/albertmatyi/meteor-hangs.git
cd meteor-hangs
meteor
http://localhost:3000/
F5
, Ctrl + R
or Cmd + R
)
The console will show how many time the resource was requested and servedUpvotes: 0
Views: 197
Reputation: 75945
This probably happens because you are using middleware that has blocking file I/O ops. The thing is for every page load, Meteor initially has to go through each middleware handler and run it before a page can be served.
The reason you are probably having this issue is that the operation you are doing is I/O intensive and its blocking the rest of the middleware from operating while it is awaiting the previous tasks to complete. (Keep in mind javascript is asynchronous but file I/O is blocking).
There isn't an easy way passed this. Immediate ideas that come to mind are to somehow use a memory buffer or something for this, or ensure that it only runs for the specific path (such as /upload
instead of for all paths. This way you would not be inconvenienced so much.
The reason the wget operation works is there is no other javascript called. For each page load meteor has a couple of dozen javascript files for each module it has that the browser will call (which in turn each file request will call the middlware too). It will wait for the js before the page is served.
What I would suggest, to keep things simple, is to only do the sendFile
operation if the route matches a specific pattern, such as /upload
. This way it is not run if you use http://localhost:3000
.
Something a bit like this (which will only work on /upload
var url = Npm.require('url');
WebApp.connectHandlers.use(function(req, res, next) {
var path = url.parse(req.url).pathname;
if(path != '/upload') next()
sendFile(req, res, '/penken.jpg');
});
Upvotes: 1