feat(backend): make FeedSourceProvider async (#77)

* feat(backend): make FeedSourceProvider async

Make feedSourceForUser and FeedSourceProviderFn return promises.
Use Promise.allSettled to tolerate partial provider failures.
Guard concurrent getOrCreate calls with in-flight promise dedup.
Return 503 from HTTP handlers when session creation fails.

Co-authored-by: Ona <no-reply@ona.com>

* fix(backend): handle remove() during in-flight session creation

Cancel pending getOrCreate when remove() is called mid-flight.
Destroy the resulting session to prevent it from leaking.

Co-authored-by: Ona <no-reply@ona.com>

---------

Co-authored-by: Ona <no-reply@ona.com>
This commit is contained in:
2026-03-15 22:57:19 +00:00
committed by GitHub
parent 8eedd1f4fd
commit 0b51b97f6c
9 changed files with 255 additions and 76 deletions

View File

@@ -33,7 +33,14 @@ export function registerFeedHttpHandlers(
async function handleGetFeed(c: Context<Env>) {
const user = c.get("user")!
const sessionManager = c.get("sessionManager")
const session = sessionManager.getOrCreate(user.id)
let session
try {
session = await sessionManager.getOrCreate(user.id)
} catch (err) {
console.error("[handleGetFeed] Failed to create session:", err)
return c.json({ error: "Service unavailable" }, 503)
}
const feed = await session.feed()
@@ -46,7 +53,7 @@ async function handleGetFeed(c: Context<Env>) {
})
}
function handleGetContext(c: Context<Env>) {
async function handleGetContext(c: Context<Env>) {
const keyParam = c.req.query("key")
if (!keyParam) {
return c.json({ error: 'Invalid or missing "key" parameter: must be a JSON array' }, 400)
@@ -70,7 +77,15 @@ function handleGetContext(c: Context<Env>) {
const user = c.get("user")!
const sessionManager = c.get("sessionManager")
const session = sessionManager.getOrCreate(user.id)
let session
try {
session = await sessionManager.getOrCreate(user.id)
} catch (err) {
console.error("[handleGetContext] Failed to create session:", err)
return c.json({ error: "Service unavailable" }, 503)
}
const context = session.engine.currentContext()
const key = contextKey(...parsed)