Add exponential backoff retry to all downstream calls
New controller/retry.js wraps async calls with infinite retries, capped at 30s with jitter. Applied to: TPB search, TMDB, Emby, Ollama chat, Transmission RPC, and the status/status interval calls inherit it via a Proxy around the Transmission client. Also handles ollama package returning pre-parsed JSON objects. Signed-off-by: William Mantly <wmantly@gmail.com>
This commit is contained in:
+16
-12
@@ -5,6 +5,7 @@ const tmdb = require('>/controller/tmdb');
|
||||
const { tmdbSearch, tmdbDetails } = tmdb;
|
||||
const library = require('>/controller/library');
|
||||
const ollama = require('>/controller/ollama');
|
||||
const { fetchWithRetry, withRetry } = require('>/controller/retry');
|
||||
|
||||
// TPB numeric categories that count as Movies / TV( used for the q.php search and to
|
||||
// keep the LLM from ever seeing non-video results).
|
||||
@@ -79,13 +80,7 @@ function parseTPBHtml(html){
|
||||
async function tpbSearch(title){
|
||||
// Category 200 = all Video; we narrow to movie/tv subcats in prefilter().
|
||||
let url = `${conf.search.tpbBase}/search/${encodeURIComponent(title)}/1/99/200`;
|
||||
let res = await fetch(url, { headers: { 'User-Agent': 'Mozilla/5.0' } });
|
||||
if(!res.ok){
|
||||
let error = new Error('UpstreamError');
|
||||
error.message = `TPB search failed( ${res.status})`;
|
||||
error.status = 502;
|
||||
throw error;
|
||||
}
|
||||
let res = await fetchWithRetry(url, { headers: { 'User-Agent': 'Mozilla/5.0' } }, { label: 'tpb search' });
|
||||
return parseTPBHtml(await res.text());
|
||||
}
|
||||
|
||||
@@ -168,9 +163,12 @@ async function rankReleases(candidates, meta){
|
||||
imdb: t.imdb || null,
|
||||
}));
|
||||
|
||||
let parsed = await ollama.chatJSON(
|
||||
buildSystemPrompt(meta.title, meta.year, meta.today),
|
||||
JSON.stringify(compact)
|
||||
let parsed = await withRetry(
|
||||
() => ollama.chatJSON(
|
||||
buildSystemPrompt(meta.title, meta.year, meta.today),
|
||||
JSON.stringify(compact)
|
||||
),
|
||||
{ label: 'ollama rankReleases' }
|
||||
);
|
||||
let options = Array.isArray(parsed.options) ? parsed.options : [];
|
||||
if(!options.length) throw new Error('Model returned no options');
|
||||
@@ -278,7 +276,10 @@ function buildSeasonPrompt(title, season, today){
|
||||
|
||||
async function bestSeasonPack(candidates, meta){
|
||||
let compact = candidates.map(t => ({ name: t.name, sizeHuman: humanSize(t.size), seeders: Number(t.seeders), info_hash: t.info_hash }));
|
||||
let parsed = await ollama.chatJSON(buildSeasonPrompt(meta.title, meta.season, meta.today), JSON.stringify(compact));
|
||||
let parsed = await withRetry(
|
||||
() => ollama.chatJSON(buildSeasonPrompt(meta.title, meta.season, meta.today), JSON.stringify(compact)),
|
||||
{ label: 'ollama bestSeasonPack' }
|
||||
);
|
||||
return parsed && parsed.info_hash ? parsed : null;
|
||||
}
|
||||
|
||||
@@ -315,7 +316,10 @@ async function bestEpisodeTorrent(candidates, meta){
|
||||
`Prefer HEVC/x265, 1080p, English audio, reasonable size. Reject CAM/TS/telesync and non-English-only.`,
|
||||
`Return STRICT JSON {"info_hash":"<from candidates>","why":"one short sentence"}; if nothing suitable, {"info_hash":null}.`,
|
||||
].join(' ');
|
||||
let parsed = await ollama.chatJSON(prompt, JSON.stringify(compact));
|
||||
let parsed = await withRetry(
|
||||
() => ollama.chatJSON(prompt, JSON.stringify(compact)),
|
||||
{ label: 'ollama bestEpisodeTorrent' }
|
||||
);
|
||||
return parsed && parsed.info_hash ? parsed : null;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user