Convert ItemActor from a single actor into a ractor::factory worker pool to remove the single-mailbox bottleneck on the item-detail read path.
Why
ractor actors process their mailbox sequentially, so the lone ItemActor (src/web/item.rs:63, ref ITEM_ACTOR) serialises every item-detail request even though Surreal<Db> is cheap to clone (Arc) and queries can run concurrently. This is the hot read path (dependency/dependant graph traversals).
Scope
- Implement an
ItemWorker (factory::Worker) that wraps the existing free fn get_item (src/web/item.rs:114) and holds its own cloned Surreal<Db>.
- Add a
WorkerBuilder that clones the DB handle per worker.
- Build the factory in
src/actors.rs in place of the /item actor spawn (src/actors.rs:181); store the factory ref in ITEM_ACTOR.
- Update the
get / app_from_item handlers (src/web/item.rs:366, :382) to submit jobs; keep call!-style request/response so endpoint signatures are unchanged.
- Routing: start with
RoundRobinRouting (workers are stateless; no per-worker warmup). Consider StickyQueuerRouting by IItemID only if benchmarks show a cache-locality win.
- Use a bounded job queue so a flood produces backpressure rather than unbounded memory growth.
Correctness
Surreal<Db> is Arc-backed and safe to share across workers; reads have no shared mutable state. (This is why write actors like PropertiesActor are intentionally left serialised.)
Note / alternative
The simplest throughput fix is to drop the actor indirection and query DB_POOL directly from the handler, as list already does. The factory is the chosen approach for its queueing/backpressure/stats — confirm that's the trade we want.
Depends on
Tests
- Existing
get_item regression tests (src/web/item.rs:397) must keep passing unchanged.
- Add a concurrency smoke test: N concurrent
Gets through the factory all succeed.
Parent: #51
Convert
ItemActorfrom a single actor into aractor::factoryworker pool to remove the single-mailbox bottleneck on the item-detail read path.Why
ractoractors process their mailbox sequentially, so the loneItemActor(src/web/item.rs:63, refITEM_ACTOR) serialises every item-detail request even thoughSurreal<Db>is cheap to clone (Arc) and queries can run concurrently. This is the hot read path (dependency/dependant graph traversals).Scope
ItemWorker(factory::Worker) that wraps the existing free fnget_item(src/web/item.rs:114) and holds its own clonedSurreal<Db>.WorkerBuilderthat clones the DB handle per worker.src/actors.rsin place of the/itemactor spawn (src/actors.rs:181); store the factory ref inITEM_ACTOR.get/app_from_itemhandlers (src/web/item.rs:366,:382) to submit jobs; keepcall!-style request/response so endpoint signatures are unchanged.RoundRobinRouting(workers are stateless; no per-worker warmup). ConsiderStickyQueuerRoutingbyIItemIDonly if benchmarks show a cache-locality win.Correctness
Surreal<Db>is Arc-backed and safe to share across workers; reads have no shared mutable state. (This is why write actors likePropertiesActorare intentionally left serialised.)Note / alternative
The simplest throughput fix is to drop the actor indirection and query
DB_POOLdirectly from the handler, aslistalready does. The factory is the chosen approach for its queueing/backpressure/stats — confirm that's the trade we want.Depends on
Tests
get_itemregression tests (src/web/item.rs:397) must keep passing unchanged.Gets through the factory all succeed.Parent: #51