Skip to content

Commit a422cc2

Browse files
committed
fix(backend): enforce single-worker deployment for in-memory job tracking
Model-download and global-reclustering job state lives in per-worker memory, so running multiple workers would let a job start in one worker while status polls hit another (404s, duplicate jobs). Hardcode the server to a single worker in run.sh and run-server.ps1 (removing the WORKERS override) and document the constraint at the in-memory state. Replaces the previous best-effort startup warning, which could not observe the real worker count.
1 parent ffec8bf commit a422cc2

3 files changed

Lines changed: 14 additions & 23 deletions

File tree

backend/main.py

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -64,23 +64,11 @@ async def lifespan(app: FastAPI):
6464
db_create_albums_table()
6565
db_create_album_images_table()
6666
db_create_metadata_table()
67-
# Model-download and global-reclustering job tracking is in-memory and
68-
# per-worker. With more than one worker, a job started in one worker is
69-
# invisible to the others, so status polls can miss it and duplicate jobs
70-
# can start. Warn loudly so deployments keep a single worker (WORKERS=1).
71-
try:
72-
worker_count = int(os.environ.get("WORKERS", "1"))
73-
except ValueError:
74-
worker_count = 1
75-
if worker_count > 1:
76-
logger.warning(
77-
"WORKERS=%s: model-download and global-reclustering job tracking is "
78-
"in-memory and per-worker. Run with a single worker (WORKERS=1) to "
79-
"avoid duplicate jobs and missed status polls.",
80-
worker_count,
81-
)
82-
8367
# Create ProcessPoolExecutor and attach it to app.state
68+
# NOTE: model-download and global-reclustering job tracking is in-memory and
69+
# per-worker, so the server is launched with a single worker (see run.sh /
70+
# run-server.ps1). Keep it that way unless that state is moved to a shared
71+
# store.
8472
app.state.executor = ProcessPoolExecutor(max_workers=1)
8573

8674
# Start the SSE model download cleanup task

backend/run-server.ps1

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,14 @@ if ($args[0] -eq "--test") {
4444
Start-Sleep -Seconds 3
4545
}
4646
} else {
47-
# Get the WORKERS environment variable or use a default value
48-
$workers = if ($env:WORKERS) { $env:WORKERS } else { "1" }
49-
Write-Host "WORKERS: $workers"
47+
# Model-download and global-reclustering job tracking is in-memory and
48+
# per-worker, so the server must run with a single worker; a job started in
49+
# one worker would be invisible to others (missed status polls, duplicate
50+
# jobs). Do not raise the worker count above 1.
5051

5152
# Start the Hypercorn server
5253
$process = Start-Process -FilePath "hypercorn" `
53-
-ArgumentList "main:app --workers $workers --bind 0.0.0.0:8000" `
54+
-ArgumentList "main:app --workers 1 --bind 0.0.0.0:8000" `
5455
-PassThru
5556

5657
# Wait for process termination or Ctrl+C

backend/run.sh

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ if [[ $1 == "--test" ]]; then
2121
sleep 3
2222
done
2323
else
24-
# print the value of the WORKERS environment variable
25-
echo "WORKERS: ${WORKERS:-1}"
26-
hypercorn main:app --workers ${WORKERS:-1} --bind 0.0.0.0:8000
24+
# Model-download and global-reclustering job tracking is in-memory and
25+
# per-worker, so the server must run with a single worker; a job started in
26+
# one worker would be invisible to others (missed status polls, duplicate
27+
# jobs). Do not raise the worker count above 1.
28+
hypercorn main:app --workers 1 --bind 0.0.0.0:8000
2729
fi

0 commit comments

Comments
 (0)