[PR #3436] [MERGED] Change PlaybackSession createFromOld to use upsert instead of create #3976

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

📋 Pull Request Information

Original PR: https://github.com/advplyr/audiobookshelf/pull/3436
Author: @mikiher
Created: 9/18/2024
Status: Merged
Merged: 9/18/2024
Merged by: @advplyr

Base: masterHead: create-playback-session-race-condition


📝 Commits (2)

  • 942bd08 Change PlaybackSession createFromOld to use upsert instead of create
  • d796849 Small change to logging of unhandled rejections

📊 Changes

2 files changed (+2 additions, -2 deletions)

View changed files

📝 server/Server.js (+1 -1)
📝 server/models/PlaybackSession.js (+1 -1)

📄 Description

This fixes #2662

While I'm not in the position to reproduce this (I don't own an iPhone), I'm pretty sure why the crash happens.

It is very likely due to duplicate /session/local requests (retries?) sent in rapid succession from the client and handled asynchronously on the server, causing a race condition.

While Request A is awaiting

let session = await Database.getPlaybackSession(sessionJson.id)

Request B is also making the same call.
both receive a null response, so each of them calls create() on the PlaybackSession model, and one of them succeeds while the other fails with UniqueConstraintError because it is trying to create a row with the same primary key.

The fix is simple - since the requests are likely identical, it is safe to use upsert instead of create, which will succeed for both A and B (this of course doesn't prevent the race condition - doing that would involve using transactions, which I think is an overkill in this case)


🔄 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/3436 **Author:** [@mikiher](https://github.com/mikiher) **Created:** 9/18/2024 **Status:** ✅ Merged **Merged:** 9/18/2024 **Merged by:** [@advplyr](https://github.com/advplyr) **Base:** `master` ← **Head:** `create-playback-session-race-condition` --- ### 📝 Commits (2) - [`942bd08`](https://github.com/advplyr/audiobookshelf/commit/942bd0859fff6c185430dc7811d81945e1f3e0e5) Change PlaybackSession createFromOld to use upsert instead of create - [`d796849`](https://github.com/advplyr/audiobookshelf/commit/d796849d7471b7af6c9a665dd89137051468a69e) Small change to logging of unhandled rejections ### 📊 Changes **2 files changed** (+2 additions, -2 deletions) <details> <summary>View changed files</summary> 📝 `server/Server.js` (+1 -1) 📝 `server/models/PlaybackSession.js` (+1 -1) </details> ### 📄 Description This fixes #2662 While I'm not in the position to reproduce this (I don't own an iPhone), I'm pretty sure why the crash happens. It is very likely due to duplicate /session/local requests (retries?) sent in rapid succession from the client and handled asynchronously on the server, causing a race condition. While Request A is awaiting ```js let session = await Database.getPlaybackSession(sessionJson.id) ``` Request B is also making the same call. both receive a null response, so each of them calls create() on the PlaybackSession model, and one of them succeeds while the other fails with UniqueConstraintError because it is trying to create a row with the same primary key. The fix is simple - since the requests are likely identical, it is safe to use upsert instead of create, which will succeed for both A and B (this of course doesn't prevent the race condition - doing that would involve using transactions, which I think is an overkill in this case) --- <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:17:47 +02:00
adam closed this issue 2026-04-25 00:17:47 +02:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/audiobookshelf#3976