Encore backend runtime on AWS ECS

This page embeds the rendered diagram and the same runtime model JSON used to generate it. The Excalidraw source is embedded in the file so it remains self-contained.

Encore backend runtime on AWS ECS: show service, auction actor, and optional IVS streamingCounts shown are for one live show with one active auction, two pending auctions, one ended auction, and two viewers across three tabs.REST + /ws forwards 8080 starts binary with_state owns owns registers conn_id websocket upgrade start_show opens room watch_show subscribe owns get_or_spawn on activate commands arms ends_at bid/start/settle SQL is source of truth bid command price/settled events fan-out events optional start_show path insert provisioning row create/reuse channel + key 5s status CAS GetStream / StopStream stream.* eventsBrowser REST/WS clientsfrontend tabs issuing REST calls andWebSocket bid connectionscount: 3 viewer tabs; seller RESTcalls as neededsource:frontend/components/studio/StudioWorkspace.tsxfrontend/components/studio/BidConsole.tsxfrontend/lib/live/backend-auction.ts ALB: encore-dev-backend-albAWS Application Load Balancer andtarget groupcount: 1 ALB + 1 target groupsource:infra/envs/dev/app/alb.tf ECS service: encore-dev-backendAWS ECS Fargate servicecount: 1 ECS service; desired_count=1todaysource:infra/envs/dev/app/ecs.tf backend ECS task/containerFargate task with one essentialbackend containercount: 1 Fargate task + 1 backendcontainersource:infra/envs/dev/app/ecs.tf Rust backend process and Axum routerHTTP/WebSocket server processcount: 1 Rust process/router on :8080source:backend/src/main.rs AppStateshared in-memory statecount: 1 per backend processsource:backend/src/main.rsbackend/src/state.rs ConnectionRegistryin-memory user-to-WebSocket revocationregistrycount: 1 registry; 3 entries / 2 userssource:backend/src/state.rsbackend/src/auth/registry.rs WebSocket connection loopsone async loop per upgraded browsertabcount: 3 loops, one per tabsource:backend/src/routes/ws.rs ShowService supervisorin-memory per-process supervisorcount: 1 per backend processsource:backend/src/state.rsbackend/src/show_service.rs Show room / ShowHandletokio broadcast sender plusdistinct-user presence mapcount: 1 live room; 3 tab receivers; 2userssource:backend/src/show_service.rs show_rx broadcast receiverstokio broadcast receivers held bysocket loopscount: 3 receivers after watch_showsource:backend/src/routes/ws.rs AuctionRegistryin-memory registry of live auctionhandlescount: 1 registry; 1 active handlesource:backend/src/show_service.rsbackend/src/auction/auction_service/registry.rs Active auction actortokio task, one per running auctioncount: 1 active actor; pending/endedhave 0source:backend/src/auction/auction_service/mod.rsbackend/src/auction/auction_service/registry.rsbackend/src/show_service.rs Auction command mailboxbounded mpsc command channel withoneshot repliescount: 1 mailbox per active actorsource:backend/src/auction/auction_service/registry.rsbackend/src/auction/auction_service/messages.rs Auction expiry timertokio Sleep armed after activationcount: 1 armed timer while auction isactivesource:backend/src/auction/auction_service/actor.rs PgBidEngine and PgAuctionStorePostgres-backed bid and lifecycleadapterscount: 1 deps set, cloned into actorsource:backend/src/main.rsbackend/src/auction/auction_bid_engine.rsbackend/src/auction/auction_service/store.rs Postgres durable truthRDS/Postgres tables and SQLconstraintscount: 1 DB; 2 show rows + 4 auctionrows heresource:migrations/000010_shows.up.sqlmigrations/000004_auctions.up.sqlmigrations/000012_one_active_auction_per_show.up.sql Streaming deps / IVS provideroptional AWS IVS control-plane clientcount: 0 baseline; 1 when IVS env issetsource:backend/src/main.rsbackend/src/config.rsbackend/src/stream_service.rs Streaming liveness pollersingle tokio interval taskcount: 0 baseline; 1 global pollerwhen streaming config existssource:backend/src/main.rsbackend/src/show_service.rs show_streams rowdurable per-show stream session rowcount: 0 baseline; 1 active row whenstreaming is onsource:migrations/000017_show_streams.up.sqlbackend/src/show_service.rsbackend/src/stream_service.rs host_ivs_channels row / AWS IVSchanneldurable host channel plus AWS IVSmedia-plane resourcecount: 0 baseline; usually 1 channelfor hostsource:migrations/000018_host_ivs_channels.up.sqlbackend/src/show_service.rs

Runtime JSON

{
  "components": [
    {
      "name": "Browser REST/WS clients",
      "kind": "frontend tabs issuing REST calls and WebSocket bid connections",
      "owner": "frontend",
      "count_when_live": "3 viewer tabs in the requested scenario; the seller studio also issues REST start/create/activate calls when the host operates the show.",
      "source": "frontend/components/studio/StudioWorkspace.tsx:231, frontend/components/studio/BidConsole.tsx:64, frontend/lib/live/backend-auction.ts:126"
    },
    {
      "name": "ALB: encore-dev-backend-alb",
      "kind": "AWS Application Load Balancer and target group",
      "owner": "infra/envs/dev/app Terraform",
      "count_when_live": "1 ALB and 1 target group; forwards /api/*, /shows/auctions, and /ws to backend:8080.",
      "source": "infra/envs/dev/app/alb.tf:1,12,92,122"
    },
    {
      "name": "ECS service: encore-dev-backend",
      "kind": "AWS ECS Fargate service",
      "owner": "infra/envs/dev/app Terraform",
      "count_when_live": "1 service with desired_count from var.backend_desired_count; the activation precondition is written for count 1.",
      "source": "infra/envs/dev/app/ecs.tf:105"
    },
    {
      "name": "backend ECS task/container",
      "kind": "Fargate task with one essential backend container",
      "owner": "ECS service encore-dev-backend",
      "count_when_live": "1 task and 1 container when desired_count=1; no per-auction ECS tasks are created.",
      "source": "infra/envs/dev/app/ecs.tf:15"
    },
    {
      "name": "Rust backend process and Axum router",
      "kind": "HTTP/WebSocket server process",
      "owner": "backend container",
      "count_when_live": "1 process listening on 0.0.0.0:8080 with REST routes and /ws.",
      "source": "backend/src/main.rs:107"
    },
    {
      "name": "AppState",
      "kind": "shared in-memory state",
      "owner": "Rust backend process",
      "count_when_live": "1 AppState per process; cloned into handlers and sockets.",
      "source": "backend/src/main.rs:168, backend/src/state.rs:13"
    },
    {
      "name": "Postgres durable truth",
      "kind": "RDS/Postgres tables and SQL constraints",
      "owner": "database layer",
      "count_when_live": "1 database; for the requested live scenario it holds 2 show rows and 4 auction rows, but only active rows drive runtime workers.",
      "source": "migrations/000010_shows.up.sql:4, migrations/000004_auctions.up.sql:6, migrations/000012_one_active_auction_per_show.up.sql:6"
    },
    {
      "name": "ShowService supervisor",
      "kind": "in-memory per-process supervisor",
      "owner": "AppState",
      "count_when_live": "1 supervisor per backend process, independent of show count.",
      "source": "backend/src/state.rs:39, backend/src/show_service.rs:908"
    },
    {
      "name": "Show room / ShowHandle",
      "kind": "tokio broadcast sender plus distinct-user presence map",
      "owner": "ShowService",
      "count_when_live": "1 room for the live show after start_show; the scheduled show has 0 rooms unless watched. In the viewer scenario: 3 tab subscriptions, 2 distinct viewers.",
      "source": "backend/src/show_service.rs:894, backend/src/show_service.rs:926, backend/src/show_service.rs:970"
    },
    {
      "name": "AuctionRegistry",
      "kind": "in-memory registry of live auction handles",
      "owner": "ShowService",
      "count_when_live": "1 registry; contains 1 handle while the single active auction actor is alive.",
      "source": "backend/src/show_service.rs:913, backend/src/auction/auction_service/registry.rs:93"
    },
    {
      "name": "Active auction actor",
      "kind": "tokio task, one per running auction",
      "owner": "AuctionRegistry",
      "count_when_live": "1 actor for the active auction. The two pending auctions and one ended auction have 0 actors.",
      "source": "backend/src/auction/auction_service/mod.rs:1, backend/src/auction/auction_service/registry.rs:106, backend/src/show_service.rs:470"
    },
    {
      "name": "Auction command mailbox",
      "kind": "bounded mpsc command channel with oneshot replies",
      "owner": "AuctionHandle / auction actor",
      "count_when_live": "1 mailbox per active actor; bid/start/close replies are ephemeral oneshot channels per command.",
      "source": "backend/src/auction/auction_service/registry.rs:20, backend/src/auction/auction_service/messages.rs:33"
    },
    {
      "name": "Auction expiry timer",
      "kind": "tokio Sleep armed after activation",
      "owner": "Active auction actor",
      "count_when_live": "1 timer while the active auction is accepting bids.",
      "source": "backend/src/auction/auction_service/actor.rs:69, backend/src/auction/auction_service/actor.rs:137"
    },
    {
      "name": "PgBidEngine and PgAuctionStore",
      "kind": "Postgres-backed bid and lifecycle adapters",
      "owner": "AuctionDeps",
      "count_when_live": "1 dependency set in AppState, cloned into the active actor; it performs bid, activation, and settlement SQL.",
      "source": "backend/src/main.rs:139, backend/src/auction/auction_bid_engine.rs:81, backend/src/auction/auction_service/store.rs:88"
    },
    {
      "name": "WebSocket connection loops",
      "kind": "one async loop per upgraded browser tab",
      "owner": "/ws route",
      "count_when_live": "3 loops for the requested viewers: one viewer has 2 tabs and another has 1 tab.",
      "source": "backend/src/routes/ws.rs:109, backend/src/routes/ws.rs:146"
    },
    {
      "name": "ConnectionRegistry",
      "kind": "in-memory user-to-WebSocket revocation registry",
      "owner": "AppState",
      "count_when_live": "1 registry with 3 live connection entries across 2 users in the requested viewer scenario.",
      "source": "backend/src/state.rs:36, backend/src/auth/registry.rs:32, backend/src/auth/registry.rs:72"
    },
    {
      "name": "show_rx broadcast receivers",
      "kind": "tokio broadcast receivers held by socket loops",
      "owner": "WebSocket connection loops",
      "count_when_live": "3 receivers when all 3 tabs have sent watch_show for the live show.",
      "source": "backend/src/routes/ws.rs:182, backend/src/routes/ws.rs:249, backend/src/routes/ws.rs:530"
    },
    {
      "name": "Streaming deps / IVS provider",
      "kind": "optional AWS IVS control-plane client",
      "owner": "AppState",
      "count_when_live": "0 when IVS_RECORDING_CONFIGURATION_ARN is unset; 1 StreamDeps and 1 IvsStreamProvider when configured.",
      "source": "backend/src/main.rs:150, backend/src/config.rs:75, backend/src/stream_service.rs:96"
    },
    {
      "name": "Streaming liveness poller",
      "kind": "single tokio interval task",
      "owner": "backend process",
      "count_when_live": "0 without streaming config; 1 process-wide poller when StreamDeps exists, regardless of show count.",
      "source": "backend/src/main.rs:180, backend/src/show_service.rs:1176"
    },
    {
      "name": "show_streams row",
      "kind": "durable per-show stream session row",
      "owner": "Postgres",
      "count_when_live": "0 in the non-streaming scenario; 1 active row for the live show when streaming is configured and DB flag streaming.enabled is true.",
      "source": "migrations/000017_show_streams.up.sql:9, backend/src/show_service.rs:715, backend/src/stream_service.rs:387"
    },
    {
      "name": "host_ivs_channels row / AWS IVS channel",
      "kind": "durable host channel plus AWS IVS media-plane resource",
      "owner": "Postgres and Amazon IVS",
      "count_when_live": "0 in the non-streaming scenario; usually 1 persistent channel for the host when streaming has been enabled for that host.",
      "source": "migrations/000018_host_ivs_channels.up.sql:13, backend/src/show_service.rs:686, backend/src/stream_service.rs:77"
    }
  ],
  "edges": [
    {
      "from": "Browser REST/WS clients",
      "to": "ALB: encore-dev-backend-alb",
      "trigger": "HTTP requests and WebSocket upgrade for /ws."
    },
    {
      "from": "Browser REST/WS clients",
      "to": "WebSocket connection loops",
      "trigger": "Each opened viewer tab creates one backend /ws connection loop after ticket exchange."
    },
    {
      "from": "ALB: encore-dev-backend-alb",
      "to": "backend ECS task/container",
      "trigger": "Target group forwards matching paths to container port 8080."
    },
    {
      "from": "backend ECS task/container",
      "to": "Rust backend process and Axum router",
      "trigger": "Container starts the backend binary."
    },
    {
      "from": "Rust backend process and Axum router",
      "to": "AppState",
      "trigger": "Router is built with shared state."
    },
    {
      "from": "AppState",
      "to": "ShowService supervisor",
      "trigger": "State owns ShowService::new()."
    },
    {
      "from": "AppState",
      "to": "ConnectionRegistry",
      "trigger": "State owns ConnectionRegistry::new()."
    },
    {
      "from": "POST /api/v1/shows/{id}/start",
      "to": "Show room / ShowHandle",
      "trigger": "ShowService.start_show commits live status, then opens the room."
    },
    {
      "from": "POST /api/v1/shows/{id}/auctions",
      "to": "Postgres durable truth",
      "trigger": "Create auction inserts item plus pending auction rows; no actor is spawned."
    },
    {
      "from": "POST /api/v1/shows/{id}/auctions/{auction_id}/activate",
      "to": "AuctionRegistry",
      "trigger": "ShowService.activate_auction validates show/auction state and calls get_or_spawn."
    },
    {
      "from": "AuctionRegistry",
      "to": "Active auction actor",
      "trigger": "get_or_spawn creates one actor task and handle for the auction_id."
    },
    {
      "from": "Active auction actor",
      "to": "Auction expiry timer",
      "trigger": "Successful Start activates the DB row and arms Sleep until ends_at."
    },
    {
      "from": "Active auction actor",
      "to": "PgBidEngine and PgAuctionStore",
      "trigger": "Start, bid, expiry, and close commands call the DB-backed adapters."
    },
    {
      "from": "PgBidEngine and PgAuctionStore",
      "to": "Postgres durable truth",
      "trigger": "activation.sql, bid_lead_cte.sql, settlement.sql, and early-close settlement update rows atomically."
    },
    {
      "from": "WebSocket connection loops",
      "to": "ConnectionRegistry",
      "trigger": "Each /ws connection consumes a ticket and registers one conn_id."
    },
    {
      "from": "WebSocket connection loops",
      "to": "show_rx broadcast receivers",
      "trigger": "watch_show subscribes the socket to the show room."
    },
    {
      "from": "show_rx broadcast receivers",
      "to": "Show room / ShowHandle",
      "trigger": "Each subscribed socket holds a broadcast receiver."
    },
    {
      "from": "WebSocket connection loops",
      "to": "Active auction actor",
      "trigger": "bid messages are sent to the actor handle and answered on the same socket."
    },
    {
      "from": "Active auction actor",
      "to": "ShowService supervisor",
      "trigger": "Accepted bids publish price events through publish_for_auction; close paths publish settlement events."
    },
    {
      "from": "ShowService supervisor",
      "to": "Show room / ShowHandle",
      "trigger": "Show events are sent on the per-show broadcast channel."
    },
    {
      "from": "Show room / ShowHandle",
      "to": "WebSocket connection loops",
      "trigger": "price, settled, stream.*, and viewer_count events fan out to all watching tabs."
    },
    {
      "from": "Streaming deps / IVS provider",
      "to": "host_ivs_channels row / AWS IVS channel",
      "trigger": "start_show streaming path ensures or creates the host channel and fetches the stream key."
    },
    {
      "from": "Streaming deps / IVS provider",
      "to": "show_streams row",
      "trigger": "start_show inserts a provisioning stream row when streaming.enabled is true."
    },
    {
      "from": "Streaming liveness poller",
      "to": "show_streams row",
      "trigger": "Every 5s poll reads active stream rows and updates status with a monotonic CAS."
    },
    {
      "from": "Streaming liveness poller",
      "to": "host_ivs_channels row / AWS IVS channel",
      "trigger": "Poller calls IVS GetStream; teardown calls StopStream."
    },
    {
      "from": "show_streams row",
      "to": "Show room / ShowHandle",
      "trigger": "Liveness transitions publish stream.live or stream.degraded events."
    }
  ],
  "scenarios": {
    "live_show": {
      "assumptions": [
        "The three viewer tabs are watching the live show.",
        "The active auction was activated through the current REST path used by the studio UI, not by a legacy WS start_auction message.",
        "Streaming is not configured or the DB streaming.enabled flag is false."
      ],
      "running": {
        "ecs": "1 ECS service, 1 Fargate task, 1 backend container, 1 Rust process, 1 Axum router.",
        "app_state": "1 AppState, 1 ShowService, 1 AuctionRegistry, 1 ConnectionRegistry, 1 PgBidEngine/PgAuctionStore dependency set.",
        "shows": "Live show: 1 in-memory ShowHandle room. Scheduled show: only a Postgres row, 0 room unless someone watches it.",
        "auctions": "Active auction: 1 actor task, 1 mailbox, 1 expiry timer, 1 registry handle. Two pending auctions: Postgres rows only, 0 actors. One ended auction: Postgres row only, 0 actors.",
        "viewers": "3 WebSocket socket loops, 3 ConnectionRegistry entries, 3 show_rx receivers, 2 distinct viewer IDs in the ShowHandle presence map.",
        "host_notifications": "0 host-notifier channels on the REST activation path; REST activation passes notify=None.",
        "durable_rows": "Postgres has 2 show rows and 4 auction rows for this scenario; the unique partial index allows only one active auction per show."
      },
      "not_running": [
        "No per-show ECS task.",
        "No per-auction ECS task or process.",
        "No actor for pending auctions.",
        "No actor for ended auctions.",
        "No streaming liveness poller or IVS runtime path in the baseline non-streaming case."
      ]
    },
    "streaming_on": {
      "assumptions": [
        "IVS_RECORDING_CONFIGURATION_ARN is set in the backend environment.",
        "The Postgres app_settings row streaming.enabled is true.",
        "The same live show was started through ShowService.start_show with streaming enabled."
      ],
      "running": {
        "baseline": "Everything from live_show is still running.",
        "stream_deps": "1 StreamDeps and 1 IvsStreamProvider in AppState.",
        "liveness": "1 process-wide liveness poller task, not one per show.",
        "stream_session": "1 active show_streams row for the live show. It starts as provisioning and later becomes live or degraded based on IVS GetStream.",
        "host_channel": "1 durable host_ivs_channels row and 1 persistent AWS IVS channel for the host, created lazily if the host did not already have one.",
        "media": "The backend never carries media bytes. If the host is broadcasting to IVS, IVS has 1 live stream on that channel; if the host has not connected OBS, the backend still only has the provisioning/degraded row plus poller.",
        "credentials": "The stream key is fetched from IVS on demand and returned to the host; it is not stored in Postgres."
      },
      "not_running": [
        "No SQS or EventBridge stream consumer.",
        "No per-show stream worker task.",
        "No extra auction actor for pending or ended auctions."
      ]
    },
    "after_restart": {
      "assumptions": [
        "The process restarts while the DB still says one show is live and one auction is active.",
        "No browser tab has reconnected yet.",
        "This describes the immediate post-start state before any request recreates in-memory rooms."
      ],
      "running": {
        "ecs": "1 replacement backend process in the same single-task ECS service.",
        "app_state": "A fresh AppState exists with a fresh ShowService, fresh empty AuctionRegistry, fresh empty BroadcastState, fresh ConnectionRegistry, and fresh in-memory ticket store.",
        "shows": "The live and scheduled shows still exist in Postgres, but there are 0 in-memory ShowHandle rooms until start_show retry or watch_show opens/subscribes one.",
        "auctions": "The active, pending, and ended auctions still exist in Postgres. There are 0 auction actor tasks, 0 auction mailboxes, 0 auction expiry timers, and 0 registry handles because the code does not rehydrate actors on boot.",
        "viewers": "0 WebSocket loops, 0 ConnectionRegistry entries, 0 show_rx receivers before reconnect.",
        "auction_effect": "The active auction will not expire by an in-process timer until an actor exists. REST close_auction can settle directly with PgAuctionStore when no actor is found; WS bids fail with auction_unavailable because auction_handle returns None.",
        "streaming_effect": "If streaming is configured, the single liveness poller starts at boot and scans active show_streams rows, but it does not recreate auction actors or show rooms."
      },
      "not_running": [
        "No previous WebSocket connection loops survive restart.",
        "No previous broadcast receivers survive restart.",
        "No auction actor or expiry timer is recreated from the active auction row."
      ]
    }
  }
}

Scenario Short Answers

{
  "live_show": {
    "assumptions": [
      "The three viewer tabs are watching the live show.",
      "The active auction was activated through the current REST path used by the studio UI, not by a legacy WS start_auction message.",
      "Streaming is not configured or the DB streaming.enabled flag is false."
    ],
    "running": {
      "ecs": "1 ECS service, 1 Fargate task, 1 backend container, 1 Rust process, 1 Axum router.",
      "app_state": "1 AppState, 1 ShowService, 1 AuctionRegistry, 1 ConnectionRegistry, 1 PgBidEngine/PgAuctionStore dependency set.",
      "shows": "Live show: 1 in-memory ShowHandle room. Scheduled show: only a Postgres row, 0 room unless someone watches it.",
      "auctions": "Active auction: 1 actor task, 1 mailbox, 1 expiry timer, 1 registry handle. Two pending auctions: Postgres rows only, 0 actors. One ended auction: Postgres row only, 0 actors.",
      "viewers": "3 WebSocket socket loops, 3 ConnectionRegistry entries, 3 show_rx receivers, 2 distinct viewer IDs in the ShowHandle presence map.",
      "host_notifications": "0 host-notifier channels on the REST activation path; REST activation passes notify=None.",
      "durable_rows": "Postgres has 2 show rows and 4 auction rows for this scenario; the unique partial index allows only one active auction per show."
    },
    "not_running": [
      "No per-show ECS task.",
      "No per-auction ECS task or process.",
      "No actor for pending auctions.",
      "No actor for ended auctions.",
      "No streaming liveness poller or IVS runtime path in the baseline non-streaming case."
    ]
  },
  "streaming_on": {
    "assumptions": [
      "IVS_RECORDING_CONFIGURATION_ARN is set in the backend environment.",
      "The Postgres app_settings row streaming.enabled is true.",
      "The same live show was started through ShowService.start_show with streaming enabled."
    ],
    "running": {
      "baseline": "Everything from live_show is still running.",
      "stream_deps": "1 StreamDeps and 1 IvsStreamProvider in AppState.",
      "liveness": "1 process-wide liveness poller task, not one per show.",
      "stream_session": "1 active show_streams row for the live show. It starts as provisioning and later becomes live or degraded based on IVS GetStream.",
      "host_channel": "1 durable host_ivs_channels row and 1 persistent AWS IVS channel for the host, created lazily if the host did not already have one.",
      "media": "The backend never carries media bytes. If the host is broadcasting to IVS, IVS has 1 live stream on that channel; if the host has not connected OBS, the backend still only has the provisioning/degraded row plus poller.",
      "credentials": "The stream key is fetched from IVS on demand and returned to the host; it is not stored in Postgres."
    },
    "not_running": [
      "No SQS or EventBridge stream consumer.",
      "No per-show stream worker task.",
      "No extra auction actor for pending or ended auctions."
    ]
  },
  "after_restart": {
    "assumptions": [
      "The process restarts while the DB still says one show is live and one auction is active.",
      "No browser tab has reconnected yet.",
      "This describes the immediate post-start state before any request recreates in-memory rooms."
    ],
    "running": {
      "ecs": "1 replacement backend process in the same single-task ECS service.",
      "app_state": "A fresh AppState exists with a fresh ShowService, fresh empty AuctionRegistry, fresh empty BroadcastState, fresh ConnectionRegistry, and fresh in-memory ticket store.",
      "shows": "The live and scheduled shows still exist in Postgres, but there are 0 in-memory ShowHandle rooms until start_show retry or watch_show opens/subscribes one.",
      "auctions": "The active, pending, and ended auctions still exist in Postgres. There are 0 auction actor tasks, 0 auction mailboxes, 0 auction expiry timers, and 0 registry handles because the code does not rehydrate actors on boot.",
      "viewers": "0 WebSocket loops, 0 ConnectionRegistry entries, 0 show_rx receivers before reconnect.",
      "auction_effect": "The active auction will not expire by an in-process timer until an actor exists. REST close_auction can settle directly with PgAuctionStore when no actor is found; WS bids fail with auction_unavailable because auction_handle returns None.",
      "streaming_effect": "If streaming is configured, the single liveness poller starts at boot and scans active show_streams rows, but it does not recreate auction actors or show rooms."
    },
    "not_running": [
      "No previous WebSocket connection loops survive restart.",
      "No previous broadcast receivers survive restart.",
      "No auction actor or expiry timer is recreated from the active auction row."
    ]
  }
}