[PR #2343] [MERGED] Simple API Caching for /libraries* requests #3698

Closed
opened 2026-04-25 00:16:42 +02:00 by adam · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/advplyr/audiobookshelf/pull/2343
Author: @mikiher
Created: 11/23/2023
Status: Merged
Merged: 11/26/2023
Merged by: @advplyr

Base: masterHead: caching


📝 Commits (10+)

📊 Changes

8 files changed (+357 additions, -17 deletions)

View changed files

📝 package-lock.json (+195 -13)
📝 package.json (+1 -0)
📝 server/Server.js (+3 -1)
📝 server/SocketAuthority.js (+2 -2)
server/managers/ApiCacheManager.js (+54 -0)
📝 server/models/User.js (+3 -1)
📝 server/routers/ApiRouter.js (+2 -0)
test/server/managers/ApiCacheManager.test.js (+97 -0)

📄 Description

/libraries* API requests usually fire complex database queries, and those queries exhibit (at least on my setup) inconsistent latencies. In some cases, the same query takes 1-2 orders of magnitude longer to complete (I did not dig deeply into the reasons).
In addition, JSON-stringifying the query results is also expensive.

This adds a simple middleware for caching GET API /libraries* requests.

  • The cache is a simple in-memory LRU cache with a maximum size and maximum number of items.
  • Cache keys are user+url, and cache values are the raw response strings (post-stringify)
  • There's no TTL (except for one special case)
    • The only case in which a TTL is set is for /personalized requests, since these have a Discover component which returns random books from the library that change on every request. I thought a 30 minutes TTL is a good compromise for this feature. In the future, I think the various /personalized components should probably be requested and loaded separately, and in parallel
  • Cache is currently invalidated when any database change occurs (not optimal, but wanted to keep it very simple for V1).
    • Incidentally, The cache is also invalidated when the browser page is reloaded with F5/Ctrl-R (this is a side effect of a database user update that happens during socket re-authentication), which seems like a good thing.

This seems to improve UI response times visibly (especially when client and server are on the same host), and reduces UI hanging due to query latency inconsistencies.


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/advplyr/audiobookshelf/pull/2343 **Author:** [@mikiher](https://github.com/mikiher) **Created:** 11/23/2023 **Status:** ✅ Merged **Merged:** 11/26/2023 **Merged by:** [@advplyr](https://github.com/advplyr) **Base:** `master` ← **Head:** `caching` --- ### 📝 Commits (10+) - [`4dec8c2`](https://github.com/advplyr/audiobookshelf/commit/4dec8c265d15fef8ea65b74690354684e51eb369) Add ApiCacheManager - [`f22f336`](https://github.com/advplyr/audiobookshelf/commit/f22f3361d5f8e853fce29290909aa62ea9ab3c15) Add timing utils - [`6a72210`](https://github.com/advplyr/audiobookshelf/commit/6a722102c5f2b0e948162710652d00945ee4c475) Use ApiCacheManager & timing middleware - [`4299627`](https://github.com/advplyr/audiobookshelf/commit/4299627f5f58b9ab50835d142aa7350120ef774a) Add lru-cache dependency - [`107b4b8`](https://github.com/advplyr/audiobookshelf/commit/107b4b83c1350401b96d3fbdf3db0b691eceef6c) Add cache middleware to most /libraries get requests - [`5aeb6ad`](https://github.com/advplyr/audiobookshelf/commit/5aeb6ade729ca071a4b8079e218ac9afa842d686) Merge branch 'caching' of https://github.com/mikiher/audiobookshelf into caching - [`d944eca`](https://github.com/advplyr/audiobookshelf/commit/d944ecaa2195215883e62861bd30ec27480b68bb) Merge branch 'caching' of https://github.com/mikiher/audiobookshelf into caching - [`5e1e748`](https://github.com/advplyr/audiobookshelf/commit/5e1e748c71d70ad2638405cec0667f84f8beee40) Add ApiCacheManager unit test - [`07d7d16`](https://github.com/advplyr/audiobookshelf/commit/07d7d164187b5b3546a8f4b50ad814f83393781b) Use a single router.get for API cache middleware - [`ab19e25`](https://github.com/advplyr/audiobookshelf/commit/ab19e25586f0e5c8fe7e65d741971a70aea16187) Remove unnecessary timing measurements ### 📊 Changes **8 files changed** (+357 additions, -17 deletions) <details> <summary>View changed files</summary> 📝 `package-lock.json` (+195 -13) 📝 `package.json` (+1 -0) 📝 `server/Server.js` (+3 -1) 📝 `server/SocketAuthority.js` (+2 -2) ➕ `server/managers/ApiCacheManager.js` (+54 -0) 📝 `server/models/User.js` (+3 -1) 📝 `server/routers/ApiRouter.js` (+2 -0) ➕ `test/server/managers/ApiCacheManager.test.js` (+97 -0) </details> ### 📄 Description /libraries* API requests usually fire complex database queries, and those queries exhibit (at least on my setup) inconsistent latencies. In some cases, the same query takes 1-2 orders of magnitude longer to complete (I did not dig deeply into the reasons). In addition, JSON-stringifying the query results is also expensive. This adds a simple middleware for caching GET API /libraries* requests. - The cache is a simple in-memory LRU cache with a maximum size and maximum number of items. - Cache keys are user+url, and cache values are the raw response strings (post-stringify) - There's no TTL (except for one special case) - _The only case in which a TTL is set is for /personalized requests, since these have a Discover component which returns random books from the library that change on every request. I thought a 30 minutes TTL is a good compromise for this feature. In the future, I think the various /personalized components should probably be requested and loaded separately, and in parallel_ - Cache is currently invalidated when **_any_** database change occurs (not optimal, but wanted to keep it very simple for V1). - _Incidentally, The cache is also invalidated when the browser page is reloaded with F5/Ctrl-R (this is a side effect of a database user update that happens during socket re-authentication), which seems like a good thing._ This seems to improve UI response times visibly (especially when client and server are on the same host), and reduces UI hanging due to query latency inconsistencies. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
adam added the pull-request label 2026-04-25 00:16:42 +02:00
adam closed this issue 2026-04-25 00:16:42 +02:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/audiobookshelf#3698