Skip to content

Commit f295c3a

Browse files
committed
chore: raise security contacts worker concurrency; hardcode tuning constants
Signed-off-by: Mouad BANI <mouad-mb@outlook.com>
1 parent efba8cd commit f295c3a

5 files changed

Lines changed: 35 additions & 22 deletions

File tree

backend/.env.dist.composed

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,4 @@ CROWD_PACKAGES_DB_PASSWORD=example
3737
CROWD_PACKAGES_DB_DATABASE=packages-db
3838

3939
# security-contacts-worker
40-
SECURITY_CONTACTS_UPDATE_INTERVAL_HOURS=24
41-
SECURITY_CONTACTS_USER_AGENT="lfx-security-contacts-worker"
42-
SECURITY_CONTACTS_CONCURRENCY=20
43-
SECURITY_CONTACTS_FETCH_TIMEOUT_MS=10000
44-
SECURITY_CONTACTS_BATCH_SIZE=500
40+
SECURITY_CONTACTS_USER_AGENT="lfx-security-contacts-worker (security@linuxfoundation.org)"

backend/.env.dist.local

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -186,11 +186,7 @@ ENRICHER_REPO_UPDATE_INTERVAL_HOURS=24
186186
ENRICHER_IDLE_SLEEP_SEC=60
187187

188188
# security-contacts-worker
189-
SECURITY_CONTACTS_UPDATE_INTERVAL_HOURS=24
190189
SECURITY_CONTACTS_USER_AGENT="lfx-security-contacts-worker (security@linuxfoundation.org)"
191-
SECURITY_CONTACTS_CONCURRENCY=20
192-
SECURITY_CONTACTS_FETCH_TIMEOUT_MS=10000
193-
SECURITY_CONTACTS_BATCH_SIZE=500
194190

195191
OSSPCKGS_GCP_PROJECT=local-dev
196192
OSSPCKGS_GCS_BUCKET=local-dev

scripts/services/security-contacts-worker.yaml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ x-env-args: &env-args
77
SHELL: /bin/sh
88
SUPPRESS_NO_CONFIG_WARNING: 'true'
99
CROWD_TEMPORAL_TASKQUEUE: packages-worker
10-
SECURITY_CONTACTS_UPDATE_INTERVAL_HOURS: '24'
1110

1211
services:
1312
security-contacts-worker:

services/apps/packages_worker/src/config.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,8 @@ export function getEnricherConfig() {
4848

4949
export function getSecurityContactsConfig() {
5050
return {
51-
// A repo is re-evaluated once its contacts are older than this many hours.
52-
updateIntervalHours: requireEnvInt('SECURITY_CONTACTS_UPDATE_INTERVAL_HOURS'),
5351
// Sent on all registry calls; crates.io rejects requests without an identifying UA.
5452
userAgent: requireEnv('SECURITY_CONTACTS_USER_AGENT'),
55-
// Lower than the enricher: each repo fans out to several HTTP calls across extractors
56-
concurrency: parseInt(process.env.SECURITY_CONTACTS_CONCURRENCY ?? '20', 10),
57-
fetchTimeoutMs: parseInt(process.env.SECURITY_CONTACTS_FETCH_TIMEOUT_MS ?? '10000', 10),
58-
batchSize: parseInt(process.env.SECURITY_CONTACTS_BATCH_SIZE ?? '500', 10),
5953
}
6054
}
6155

services/apps/packages_worker/src/security-contacts/processBatch.ts

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,20 @@ export interface BatchResult {
3030
processed: number
3131
}
3232

33+
// Two-tier refresh cadence (the worker runs on a daily cron). Just under 24h/168h so a repo
34+
// processed at ~06:00 is eligible again at the next daily/weekly tick rather than slipping a day.
35+
const DAILY_INTERVAL_HOURS = 20 // repos never evaluated or with no contacts yet
36+
const WEEKLY_INTERVAL_HOURS = 156 // already-enriched repos (have contacts)
37+
38+
// Tuned for throughput within the platform ceilings:
39+
// - CONCURRENCY: parallel repos; safe against GitHub REST secondary limits given the token pool.
40+
// - FETCH_TIMEOUT_MS: generous enough for slow registries (Maven metadata/POM) without hanging slots.
41+
// - BATCH_SIZE: bounded by the 30-min activity timeout (worst case: an all-cargo batch throttled
42+
// to crates.io's 1 req/s finishes ~8 min).
43+
const CONCURRENCY = 100
44+
const FETCH_TIMEOUT_MS = 15000
45+
const BATCH_SIZE = 500
46+
3347
const EXTRACTORS: Extractor[] = [
3448
extractSecurityInsights, // A1
3549
extractPvr, // A2
@@ -46,7 +60,7 @@ interface SweepRow {
4660
packages: RepoPackage[] | null
4761
}
4862

49-
async function fetchBatch(qx: QueryExecutor, config: Config): Promise<SweepRow[]> {
63+
async function fetchBatch(qx: QueryExecutor): Promise<SweepRow[]> {
5064
return qx.select(
5165
`
5266
SELECT r.id::text AS id,
@@ -58,14 +72,28 @@ async function fetchBatch(qx: QueryExecutor, config: Config): Promise<SweepRow[]
5872
JOIN packages p ON p.id = pr.package_id AND p.is_critical
5973
WHERE r.host = 'github'
6074
AND (
75+
-- never evaluated → always eligible
6176
r.contacts_last_refreshed IS NULL
62-
OR r.contacts_last_refreshed < NOW() - INTERVAL '$(updateIntervalHours) hours'
77+
-- evaluated but no contacts found yet → retry on the daily cadence
78+
OR (
79+
NOT EXISTS (SELECT 1 FROM security_contacts sc WHERE sc.repo_id = r.id)
80+
AND r.contacts_last_refreshed < NOW() - INTERVAL '$(dailyIntervalHours) hours'
81+
)
82+
-- already enriched (has contacts) → refresh on the weekly cadence
83+
OR (
84+
EXISTS (SELECT 1 FROM security_contacts sc WHERE sc.repo_id = r.id)
85+
AND r.contacts_last_refreshed < NOW() - INTERVAL '$(weeklyIntervalHours) hours'
86+
)
6387
)
6488
GROUP BY r.id
6589
ORDER BY r.id
6690
LIMIT $(batchSize)
6791
`,
68-
{ batchSize: config.batchSize, updateIntervalHours: config.updateIntervalHours },
92+
{
93+
batchSize: BATCH_SIZE,
94+
dailyIntervalHours: DAILY_INTERVAL_HOURS,
95+
weeklyIntervalHours: WEEKLY_INTERVAL_HOURS,
96+
},
6997
)
7098
}
7199

@@ -130,17 +158,17 @@ async function processRepo(
130158
}
131159

132160
export async function processBatch(qx: QueryExecutor, config: Config): Promise<BatchResult> {
133-
const batch = await fetchBatch(qx, config)
161+
const batch = await fetchBatch(qx)
134162
if (batch.length === 0) return { processed: 0 }
135163

136164
const deps: ExtractorDeps = {
137-
fetchTimeoutMs: config.fetchTimeoutMs,
165+
fetchTimeoutMs: FETCH_TIMEOUT_MS,
138166
userAgent: config.userAgent,
139167
getToken: getSecurityContactsToken,
140168
}
141169

142170
const targets = batch.map(toTarget)
143-
await runWithConcurrency(targets, config.concurrency, (target) => processRepo(target, deps, qx))
171+
await runWithConcurrency(targets, CONCURRENCY, (target) => processRepo(target, deps, qx))
144172

145173
log.info({ processed: targets.length }, 'Security contacts batch complete')
146174
return { processed: targets.length }

0 commit comments

Comments
 (0)