Session 7d: Audit fixes - rate limiting, error leak, parallel parlays, analyze cache, bundle analyzer
This commit is contained in:
@@ -23,12 +23,22 @@ async function scanParlay(user, legs) {
|
||||
}
|
||||
}
|
||||
|
||||
// Analyze all legs
|
||||
const legResults = [];
|
||||
for (const leg of legs) {
|
||||
const result = await analyzeProp(leg);
|
||||
legResults.push(result);
|
||||
}
|
||||
// PERF-2 (Session 7d): analyze legs in parallel. Each call is an
|
||||
// independent upstream lookup, so a 6-leg parlay is ~6x faster here
|
||||
// than the old sequential loop. allSettled preserves leg order and
|
||||
// lets a single failed leg surface as an error stub instead of
|
||||
// crashing the whole parlay.
|
||||
const settled = await Promise.allSettled(legs.map((leg) => analyzeProp(leg)));
|
||||
const legResults = settled.map((s, i) => {
|
||||
if (s.status === 'fulfilled') return s.value;
|
||||
return {
|
||||
...legs[i],
|
||||
error: s.reason?.message || 'analysis_failed',
|
||||
grade: 'F',
|
||||
confidence: 0,
|
||||
reasoning: { summary: 'Analysis failed for this leg.' },
|
||||
};
|
||||
});
|
||||
|
||||
// Fetch odds data for correlation detection (spreads, game context)
|
||||
let spreads = [];
|
||||
@@ -81,28 +91,30 @@ async function scanParlay(user, legs) {
|
||||
correlationFlags
|
||||
);
|
||||
|
||||
// Write to database
|
||||
const pickIds = [];
|
||||
for (const leg of legResults) {
|
||||
const { data: pick, error } = await supabase
|
||||
// PERF-2 (Session 7d): one batched insert for every leg's pick row
|
||||
// instead of N sequential inserts. Supabase preserves insert order in
|
||||
// the returned data array so pickIds line up with legResults.
|
||||
const pickRows = legResults.map((leg) => ({
|
||||
user_id: user.id,
|
||||
player: leg.player,
|
||||
stat_type: leg.stat_type,
|
||||
line: leg.line,
|
||||
book: leg.book || 'unknown',
|
||||
direction: leg.direction,
|
||||
grade: leg.grade,
|
||||
edge_pct: leg.edge_pct,
|
||||
reasoning: leg.reasoning?.summary || '',
|
||||
kill_conditions: (leg.kill_conditions_triggered || []).map((k) => k.code),
|
||||
confidence: leg.confidence,
|
||||
}));
|
||||
let pickIds = [];
|
||||
if (pickRows.length > 0) {
|
||||
const { data: picksData, error: picksErr } = await supabase
|
||||
.from('picks')
|
||||
.insert({
|
||||
user_id: user.id,
|
||||
player: leg.player,
|
||||
stat_type: leg.stat_type,
|
||||
line: leg.line,
|
||||
book: leg.book || 'unknown',
|
||||
direction: leg.direction,
|
||||
grade: leg.grade,
|
||||
edge_pct: leg.edge_pct,
|
||||
reasoning: leg.reasoning?.summary || '',
|
||||
kill_conditions: (leg.kill_conditions_triggered || []).map((k) => k.code),
|
||||
confidence: leg.confidence,
|
||||
})
|
||||
.select('id')
|
||||
.single();
|
||||
|
||||
if (pick) pickIds.push(pick.id);
|
||||
.insert(pickRows)
|
||||
.select('id');
|
||||
if (picksErr) console.warn('[VYNDR] picks batch insert failed:', picksErr.message);
|
||||
pickIds = (picksData || []).map((p) => p.id);
|
||||
}
|
||||
|
||||
// Write scan session
|
||||
|
||||
Reference in New Issue
Block a user