prevent discover query crashes from restarting server

This commit is contained in:
Kevin Gatera 2026-03-03 21:37:52 -05:00
parent ce2efe6a01
commit 6183b3012c
No known key found for this signature in database
GPG key ID: F0D9F5932458CFB9
4 changed files with 79 additions and 14 deletions

View file

@ -374,19 +374,24 @@ module.exports = {
async getLibraryItemsToDiscover(library, user, include, limit) {
if (library.mediaType !== 'book') return { libraryItems: [], count: 0 }
const { libraryItems, count } = await libraryItemsBookFilters.getDiscoverLibraryItems(library.id, user, include, limit)
return {
libraryItems: libraryItems.map((li) => {
const oldLibraryItem = li.toOldJSONMinified()
if (li.rssFeed) {
oldLibraryItem.rssFeed = li.rssFeed.toOldJSONMinified()
}
if (li.mediaItemShare) {
oldLibraryItem.mediaItemShare = li.mediaItemShare
}
return oldLibraryItem
}),
count
try {
const { libraryItems, count } = await libraryItemsBookFilters.getDiscoverLibraryItems(library.id, user, include, limit)
return {
libraryItems: libraryItems.map((li) => {
const oldLibraryItem = li.toOldJSONMinified()
if (li.rssFeed) {
oldLibraryItem.rssFeed = li.rssFeed.toOldJSONMinified()
}
if (li.mediaItemShare) {
oldLibraryItem.mediaItemShare = li.mediaItemShare
}
return oldLibraryItem
}),
count
}
} catch (error) {
Logger.error(`[LibraryFilters] Failed to load discover shelf for library "${library.id}"`, error)
return { libraryItems: [], count: 0 }
}
},

View file

@ -942,7 +942,7 @@ module.exports = {
const discoverWhere = [
{
'$mediaProgresses.isFinished$': {
[Sequelize.Op.or]: [null, 0]
[Sequelize.Op.or]: [null, false]
},
'$mediaProgresses.currentTime$': {
[Sequelize.Op.or]: [null, 0]

View file

@ -0,0 +1,45 @@
const { expect } = require('chai')
const sinon = require('sinon')
const Logger = require('../../../../server/Logger')
const libraryFilters = require('../../../../server/utils/queries/libraryFilters')
const libraryItemsBookFilters = require('../../../../server/utils/queries/libraryItemsBookFilters')
describe('libraryFilters discover shelf resilience', () => {
afterEach(() => {
sinon.restore()
})
it('should return empty discover shelf when discover query fails', async () => {
sinon.stub(libraryItemsBookFilters, 'getDiscoverLibraryItems').rejects(new Error('discover failed'))
const errorStub = sinon.stub(Logger, 'error')
const result = await libraryFilters.getLibraryItemsToDiscover({ mediaType: 'book', id: 'library-1' }, { id: 'user-1' }, [], 10)
expect(result).to.deep.equal({ libraryItems: [], count: 0 })
expect(errorStub.calledWithMatch('[LibraryFilters] Failed to load discover shelf for library "library-1"')).to.equal(true)
})
it('should keep discover shelf mapping behavior when query succeeds', async () => {
const libraryItem = {
toOldJSONMinified: () => ({ id: 'item-1' }),
rssFeed: { toOldJSONMinified: () => ({ id: 'rss-1' }) },
mediaItemShare: { id: 'share-1' }
}
sinon.stub(libraryItemsBookFilters, 'getDiscoverLibraryItems').resolves({
libraryItems: [libraryItem],
count: 1
})
const result = await libraryFilters.getLibraryItemsToDiscover({ mediaType: 'book', id: 'library-1' }, { id: 'user-1' }, [], 10)
expect(result.count).to.equal(1)
expect(result.libraryItems).to.deep.equal([
{
id: 'item-1',
rssFeed: { id: 'rss-1' },
mediaItemShare: { id: 'share-1' }
}
])
})
})

View file

@ -1,5 +1,6 @@
const { expect } = require('chai')
const sinon = require('sinon')
const Sequelize = require('sequelize')
const Database = require('../../../../server/Database')
const Logger = require('../../../../server/Logger')
@ -130,4 +131,18 @@ describe('libraryItemsBookFilters postgres query safety', () => {
expect(orderExpression).to.include('"books->bookSeries"."sequence"')
})
it('should use boolean false for discover not-started media progress on postgres', async () => {
Database.sequelize = createSequelizeStub('postgres', modelStubs)
modelStubs.series.findAll.resolves([])
modelStubs.book.count.resolves(0)
modelStubs.book.findAll.resolves([])
await libraryItemsBookFilters.getDiscoverLibraryItems('library-1', { id: 'user-1', canAccessExplicitContent: true }, [], 10)
const countOptions = modelStubs.book.count.firstCall.args[0]
const progressFilter = countOptions.where[0]['$mediaProgresses.isFinished$']
expect(progressFilter[Sequelize.Op.or]).to.deep.equal([null, false])
})
})