manuel-hegner/foundry-filepicker-favorites

Too many requests from collectFiles function on ready hook (and can result in ERR_INSUFFICIENT_RESOURCES on Chrome)

Closed this issue ยท 6 comments

Hey there ๐Ÿ‘‹

The collectFiles function which runs on the Foundry ready hook can make a lot of simultaneous calls to FilePicker.browse(), sometimes several hundred.

This can lead to a resource usage spike and ERR_INSUFFICIENT_RESOURCES in the Chrome browser (bug in Chrome) and delays in other browsers.

The below image was captured by a user on The Forge:
image
In this case, the Forge server also tries to serve these hundreds of requests simultaneously which can lead to a detrimental spike in server load.

Many APIs implement server side rate limiting to prevent excessive requests being served per minute, but there are a couple of things that can be done from the client side to lighten the load as well to ensure that module users have the best experience.

  • The best improvement would be to cache the results returned by the search to localStorage, so that subsequent ready hooks or refreshes can get the results directly from cache rather than making another call.

  • It's also possible to delay the search call until the Filepicker is opened and the user performs a search in it. This will prevent the calls from being made on browser refresh and world load, which are very common events. Combined with caching, this could lead to improved performance and less strain on browser and server.

  • A less effective but simple improvement is to batch the collectFiles call promises into a small batch sizes with a brief delay between batch processing. This can help to smooth a usage spike by spreading out the calls, especially with caching (suggestion 2) if the search call on startup is mandatory.

collectFiles only runs for each source in parallel. That means it can not make simultaneous calls to a source.

That said, is the situation with the forge still a problem? I have added an optimization to the so that there are not that many requests needed (since the forge adds a recursive option). I will add the ability to add include filters and a delay to sources.

collectFiles only runs for each source in parallel. That means it can not make simultaneous calls to a source.

That said, is the situation with the forge still a problem? I have added an optimization to the so that there are not that many requests needed (since the forge adds a recursive option). I will add the ability to add include filters and a delay to sources.

The issue is that you can't do a recursive browse on the user data or the Bazaar source and it seems you're also trying to do it for these. A user with 200+ installed modules would have hundreds, if not potentially thousands of requests launched as soon as they login. Same for every one of their players. That's completely unnecessary and will slow down the browser to a crawl most times (Anything that does over 500 requests will generally cause Chrome itself to start lagging as it can't handle that number of requests efficiently).

As @rikmarais suggested, the most efficient thing here would be to not start recursively browsing until the user actually attempts to use the FilePicker, and also to cache the browse results so you don't need to do it every time for things you know can't have changed.
For example, keep a cache of all the files on a per-module+version basis, and write that to filepicker-favorites-cache.json when you browse the modules folder, you can also check game.modules in the Foundry API to check the version of each module, if the module name+version is already in your cache, use that list of files without browsing the folder recursively. If it's not, or if the version changed, then browse it and update your cache file.

Not, it doesn't do more than one at a time, but it does them one after the other, and when it takes only a few milliseconds to do a request, you end up with multiple requests per second happening, and Chrome still doesn't like that very much. Also, it means that the user's browser keeps doing browse for multiple minutes, slowing them down for the first few minutes of game.
And yes, the caching would only be something you can do for modules/systems, not for actual user assets or non systems/modules directory (but the assets library supports recursive option so that's good at least).
It'll be different for non-Forge users because those browse requests will be going through the websocket, which won't affect chrome as much, but it would affect the gameplay still because as long as the websocket is handling a browse request, it won't be able to handle a token move or anything, since it's "one command at a time" on the websocket (also why you shouldn't actually do multiple requests in parallel, as it would cause more contention, so I'm glad you don't :) ).

I will note that the module now consistently causes Electron version of Foundry to freeze on my machine. Opening it in browser and leaving Electron run in the background is a little better but still freezes quite often, just without having to deal with Windows detecting that the software is not responsive.

The new version includes better way to filter which directories to actually index, caches the index so it does not need to be recreated every time and limits the request speed. I hope this solves these kind of problems.