Skip to content

Commit 92ff09a

Browse files
fix(backend): cap repo-index metric cardinality and add OOM diagnostics
Add Node's --heapsnapshot-near-heap-limit to the backend program so a heap snapshot is captured to a persisted directory if the process approaches its heap limit again, giving a definitive object graph instead of only a generic "JavaScript heap out of memory" crash log. Also fix an identified metric-cardinality leak: repo-scoped Prometheus metrics keyed by repo name are never cleared, so every distinct repo name observed over the process's lifetime stays resident in the registry forever, even after the repo is deleted. Remove those time series once a repo is actually deleted.
1 parent 8184cf4 commit 92ff09a

4 files changed

Lines changed: 35 additions & 1 deletion

File tree

entrypoint.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,12 @@ if [ ! -d "$DATA_CACHE_DIR" ]; then
104104
mkdir -p "$DATA_CACHE_DIR"
105105
fi
106106

107+
# Create a directory for heap snapshots. If the backend process approaches its heap
108+
# limit (e.g., due to a memory leak), Node will dump a snapshot here (see
109+
# --heapsnapshot-near-heap-limit in supervisord.conf) so the cause can be diagnosed
110+
# post-mortem instead of only seeing a generic "JavaScript heap out of memory" crash.
111+
mkdir -p "$DATA_CACHE_DIR/heap-snapshots"
112+
107113
# As of v5, SOURCEBOT_ENCRYPTION_KEY must be provided explicitly via an environment variable.
108114
# @see: https://docs.sourcebot.dev/docs/upgrade/v4-to-v5-guide
109115
if [ -z "$SOURCEBOT_ENCRYPTION_KEY" ]; then

packages/backend/src/promClient.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,4 +91,24 @@ export class PromClient {
9191
register: this.registry,
9292
});
9393
}
94+
95+
/**
96+
* Removes all time series associated with a given repo across every repo-scoped
97+
* metric. The `repo` label is a dynamic, user-controlled value (repo name), and
98+
* prom-client never forgets a label combination on its own once it's been
99+
* observed. Without this cleanup, every distinct repo name ever seen over the
100+
* process's lifetime stays resident in memory forever, even after the repo is
101+
* deleted. Call this once a repo is permanently removed (e.g., after a CLEANUP
102+
* job deletes it) to keep the registry's memory footprint bounded by the current
103+
* set of repos rather than the historical set.
104+
*/
105+
public removeRepoMetrics(repoName: string) {
106+
for (const type of ['index', 'cleanup']) {
107+
this.activeRepoIndexJobs.remove({ repo: repoName, type });
108+
this.pendingRepoIndexJobs.remove({ repo: repoName, type });
109+
this.repoIndexJobReattemptsTotal.remove({ repo: repoName, type });
110+
this.repoIndexJobFailTotal.remove({ repo: repoName, type });
111+
this.repoIndexJobSuccessTotal.remove({ repo: repoName, type });
112+
}
113+
}
94114
}

packages/backend/src/repoIndexManager.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -614,6 +614,10 @@ export class RepoIndexManager {
614614
where: { id: jobData.repoId },
615615
});
616616

617+
// The repo no longer exists, so drop its time series from the metrics
618+
// registry rather than retaining them for the lifetime of the process.
619+
this.promClient.removeRepoMetrics(repo.name);
620+
617621
logger.debug(`Completed cleanup job ${job.data.jobId} for repo ${repo.name} (id: ${repo.id})`);
618622
}
619623

supervisord.conf

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,8 @@ autorestart=true
3131
startretries=3
3232
stdout_logfile=/dev/fd/1
3333
stdout_logfile_maxbytes=0
34-
redirect_stderr=true
34+
redirect_stderr=true
35+
; Dump up to 3 heap snapshots to a persisted directory if the process approaches
36+
; its heap limit, so a real memory leak (as opposed to a transient spike) can be
37+
; diagnosed from the actual retained object graph instead of guessing from logs.
38+
environment=NODE_OPTIONS="--heapsnapshot-near-heap-limit=3 --diagnostic-dir=%(ENV_DATA_CACHE_DIR)s/heap-snapshots"

0 commit comments

Comments
 (0)