BUG-151 - REST category mutations time out (503) because they block on the main UI thread under load¶
Summary¶
eMuleBB REST category mutations (categories/create, categories/update,
categories/delete, categories/rename) are dispatched synchronously to the
main window and wait for the UI thread to service the command. On large profiles
(observed against a ~66k shared-file instance) and/or while a controller such as
aMuTorrent polls the REST API, the UI thread does not service the dispatched
message within the timeout, so the mutation returns 503 EMULE_UNAVAILABLE
("main window did not process REST command within N ms") or 503 "eMuleBB web
API is busy".
As a result, a REST controller cannot reliably create/edit/delete categories. aMuTorrent has shipped a workaround that treats eMuleBB categories as read-only (import/display/assignment only, no writes pushed to eMuleBB). This item tracks the eMuleBB-side fix so REST category management works under normal load.
Current State¶
- Category mutations run through the REST→UI dispatch path: the REST worker
PostMessagesWEB_REST_API_COMMANDtotheApp.emuledlg->m_hWndand blocks onWaitForSingleObject(..., kRestUiDispatchTimeoutMs)(WebServerJson.cpp~4513-4537). On timeout it returnsEMULE_UNAVAILABLE/ "main window did not process REST command within N ms". categories/createbuilds aCategory_Struct, callsthePrefs.AddCat+SaveCats+RefreshCategoryUi(WebServerJson.cpp~2958-2983) — work that is gated on UI-thread responsiveness.- Reproduced 2026-06-13 against
192.168.1.210:4711(66,140 shared files): - With the aMuTorrent controller polling (snapshot + per-transfer detail
calls every ~3s),
POST /api/v1/categoriesandDELETE /api/v1/categories/{id}returned503repeatedly. - With the controller stopped, the identical
DELETEreturned200immediately — confirming the failure is UI-thread contention, not a bad request.
Why This Matters¶
Controller-driven category management (aMuTorrent, Arr workflows) is part of the RC integration story. Without a fix, controllers must lock category writes and users must manage categories only in the eMuleBB GUI. The single-web-worker plus synchronous UI dispatch also means routine polling can starve mutations.
Representative Sites¶
srchybrid/WebServerJson.cpp—categories/create|update|delete|renamecommand handlers (~2958+).srchybrid/WebServerJson.cpp— REST→UI synchronous dispatch (PostMessage(WEB_REST_API_COMMAND)+WaitForSingleObject,WebServerJsonSeams::kRestUiDispatchTimeoutMs, ~4513-4537).- 503 "web API is busy" backpressure guard (single web worker).
Intended Shape¶
Candidate directions (to be evaluated, not yet decided):
- Reduce category mutations' dependence on a synchronous UI-thread round-trip: perform the preference/category-model mutation on a path that does not require the UI message pump to be idle, refreshing UI asynchronously afterwards.
- And/or make the dispatch resilient under polling load (fair queueing so a
mutation is not starved by snapshot GETs; bounded retry/backoff with a clear
Retry-After). - Keep stock category semantics and persistence (
thePrefs.AddCat/SaveCats).
Scope Constraints¶
- eMuleBB-side (C++ app). Under the RC2 soft freeze this is post-0.7.3 unless explicitly reclassified as release-blocking.
- Out of scope: the aMuTorrent-side lock, which already landed
(
clientMetaemulebb.capabilities.categoryWrite = false; CategoryManager skips read-only backends for category writes; web UI hides create/edit/delete for read-only ED2K backends).
Acceptance Criteria¶
- [ ]
POST/PUT/DELETEcategory REST mutations succeed under normal controller polling on a large (tens-of-thousands shared files) profile, without503 EMULE_UNAVAILABLE. - [ ] Category model and persistence semantics are unchanged (categories created via REST appear identically to GUI-created ones).
- [ ] A controller polling the snapshot endpoint cannot indefinitely starve a category mutation.
- [ ] Debug, Release, and diagnostics Release x64 app builds pass before commit.
Notes¶
- Provenance: operator testing of the aMuTorrent eMuleBB integration on 2026-06-13 (uploads/servers/history-metadata adapter fixes landed in the controller in the same session; category creation was locked there pending this fix).
- Related: the single-web-worker "busy" 503 backpressure interacts with this; consider together.