← back to Ventura Corridor
feat(news): nightly launchd jobs + patient summarizer backoff
0a78f9e7240402b261b0e1eb7a478e2e31275f81 · 2026-05-07 10:38:50 -0700 · SteveStudio2
- launchd/com.steve.ventura-corridor-news-scrape.plist
Runs `npm run crawl:news` at 03:15 daily. Polite defaults
(4 concurrent, 500ms host gap, 10s timeout).
- launchd/com.steve.ventura-corridor-news-summarize.plist
Runs `npm run news:summarize -- --limit=200` at 05:30 daily, two hours
after the scraper, so fresh items get qwen3:14b summaries before the
morning corpus-summary email at 09:00.
- Both registered + loaded into ~/Library/LaunchAgents and copied into
the project's launchd/ dir for version-tracking + reproducibility.
- summarize_news.ts backoff bumped from 8s/16s/32s/64s (max ~2min) to
60s/120s/240s/480s/960s/1920s (max ~62min). Magazine-gen 2000-feature
runs hold Mac1 for hours; the old backoff exhausted before capacity
opened. Patient backoff lets the 05:30 launchd drain even if the
generator runs long.
Verified: launchctl list shows both plists loaded; Steve's 2000-feature
generate_features will finish before 05:30 most nights.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Files touched
A launchd/com.steve.ventura-corridor-news-scrape.plistA launchd/com.steve.ventura-corridor-news-summarize.plistM src/jobs/summarize_news.ts
Diff
commit 0a78f9e7240402b261b0e1eb7a478e2e31275f81
Author: SteveStudio2 <stevestudio2@SteveStacStudio.lan>
Date: Thu May 7 10:38:50 2026 -0700
feat(news): nightly launchd jobs + patient summarizer backoff
- launchd/com.steve.ventura-corridor-news-scrape.plist
Runs `npm run crawl:news` at 03:15 daily. Polite defaults
(4 concurrent, 500ms host gap, 10s timeout).
- launchd/com.steve.ventura-corridor-news-summarize.plist
Runs `npm run news:summarize -- --limit=200` at 05:30 daily, two hours
after the scraper, so fresh items get qwen3:14b summaries before the
morning corpus-summary email at 09:00.
- Both registered + loaded into ~/Library/LaunchAgents and copied into
the project's launchd/ dir for version-tracking + reproducibility.
- summarize_news.ts backoff bumped from 8s/16s/32s/64s (max ~2min) to
60s/120s/240s/480s/960s/1920s (max ~62min). Magazine-gen 2000-feature
runs hold Mac1 for hours; the old backoff exhausted before capacity
opened. Patient backoff lets the 05:30 launchd drain even if the
generator runs long.
Verified: launchctl list shows both plists loaded; Steve's 2000-feature
generate_features will finish before 05:30 most nights.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---
.../com.steve.ventura-corridor-news-scrape.plist | 40 ++++++++++++++++++++++
...com.steve.ventura-corridor-news-summarize.plist | 38 ++++++++++++++++++++
src/jobs/summarize_news.ts | 11 +++---
3 files changed, 85 insertions(+), 4 deletions(-)
diff --git a/launchd/com.steve.ventura-corridor-news-scrape.plist b/launchd/com.steve.ventura-corridor-news-scrape.plist
new file mode 100644
index 0000000..401f21e
--- /dev/null
+++ b/launchd/com.steve.ventura-corridor-news-scrape.plist
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>Label</key>
+ <string>com.steve.ventura-corridor-news-scrape</string>
+ <key>ProgramArguments</key>
+ <array>
+ <string>/bin/bash</string>
+ <string>-lc</string>
+ <string>cd /Users/stevestudio2/Projects/ventura-corridor && /usr/local/bin/npm run crawl:news</string>
+ </array>
+ <key>StartCalendarInterval</key>
+ <dict>
+ <key>Hour</key>
+ <integer>3</integer>
+ <key>Minute</key>
+ <integer>15</integer>
+ </dict>
+ <key>StandardOutPath</key>
+ <string>/Users/stevestudio2/Projects/ventura-corridor/logs/news-scrape.out.log</string>
+ <key>StandardErrorPath</key>
+ <string>/Users/stevestudio2/Projects/ventura-corridor/logs/news-scrape.err.log</string>
+ <key>EnvironmentVariables</key>
+ <dict>
+ <key>PATH</key>
+ <string>/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin</string>
+ <key>PGHOST</key>
+ <string>/tmp</string>
+ <key>NEWS_TIMEOUT_MS</key>
+ <string>10000</string>
+ <key>NEWS_HOST_GAP_MS</key>
+ <string>500</string>
+ <key>NEWS_CONCURRENCY</key>
+ <string>4</string>
+ </dict>
+ <key>RunAtLoad</key>
+ <false/>
+</dict>
+</plist>
diff --git a/launchd/com.steve.ventura-corridor-news-summarize.plist b/launchd/com.steve.ventura-corridor-news-summarize.plist
new file mode 100644
index 0000000..7bdfa6d
--- /dev/null
+++ b/launchd/com.steve.ventura-corridor-news-summarize.plist
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>Label</key>
+ <string>com.steve.ventura-corridor-news-summarize</string>
+ <key>ProgramArguments</key>
+ <array>
+ <string>/bin/bash</string>
+ <string>-lc</string>
+ <string>cd /Users/stevestudio2/Projects/ventura-corridor && /usr/local/bin/npm run news:summarize -- --limit=200</string>
+ </array>
+ <key>StartCalendarInterval</key>
+ <dict>
+ <key>Hour</key>
+ <integer>5</integer>
+ <key>Minute</key>
+ <integer>30</integer>
+ </dict>
+ <key>StandardOutPath</key>
+ <string>/Users/stevestudio2/Projects/ventura-corridor/logs/news-summarize.out.log</string>
+ <key>StandardErrorPath</key>
+ <string>/Users/stevestudio2/Projects/ventura-corridor/logs/news-summarize.err.log</string>
+ <key>EnvironmentVariables</key>
+ <dict>
+ <key>PATH</key>
+ <string>/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin</string>
+ <key>PGHOST</key>
+ <string>/tmp</string>
+ <key>OLLAMA_URL</key>
+ <string>http://100.94.103.98:11434</string>
+ <key>OLLAMA_MODEL</key>
+ <string>qwen3:14b</string>
+ </dict>
+ <key>RunAtLoad</key>
+ <false/>
+</dict>
+</plist>
diff --git a/src/jobs/summarize_news.ts b/src/jobs/summarize_news.ts
index e9f2808..427cf8c 100644
--- a/src/jobs/summarize_news.ts
+++ b/src/jobs/summarize_news.ts
@@ -51,11 +51,14 @@ async function callOllama(prompt: string, attempt = 0): Promise<string> {
}),
signal: AbortSignal.timeout(TIMEOUT_MS)
});
- // Mac1 magazine-gen runs the same Ollama hot — 503 "server busy" is common.
- // Backoff up to 4 times: 8s, 16s, 32s, 64s. After that surface the error.
+ // Mac1 magazine-gen runs the same Ollama hot — 503 "server busy" is common
+ // and can persist for hours on a 2000-feature run. Backoff up to 6 times:
+ // 60s, 120s, 240s, 480s, 960s, 1920s. Total ~62min wait before giving up.
+ // The summarize job is normally invoked at 5:30am via launchd long after
+ // generate_features completes, so this almost always succeeds first try.
if (res.status === 503 || res.status === 429) {
- if (attempt >= 4) throw new Error(`ollama ${res.status}: backoff exhausted`);
- const delay = 8000 * Math.pow(2, attempt);
+ if (attempt >= 6) throw new Error(`ollama ${res.status}: backoff exhausted`);
+ const delay = 60000 * Math.pow(2, attempt);
await sleep(delay);
return callOllama(prompt, attempt + 1);
}
← e8b2f73 feat(news): /api/news/recent + /news.html magazine surface
·
back to Ventura Corridor
·
feat(enrich): website-discovery resilience + category priori 828ab33 →