← back to Norma
instagram: keep ALL accounts live via cron (not just DW)
8cfcfe2a9cb03bd7a96bb969c327b6b29c16282c · 2026-08-18 14:29:26 -0700 · Steve Abrams
- refreshAllAccounts(): serialized, per-account error-isolated sweep of the whole
35-account roster (incremental by default; full+onlyIncomplete for backfill).
- live-media-refresh cron now sweeps ALL accounts hourly (was DW-only), so the
cross-account /calendar stays live for the whole roster.
- new live-media-backfill-sweep cron (daily 04:40): full-backfills up to 5 not-yet-
complete accounts/run as a safety net; no-ops once all complete.
Verified: one-shot incremental sweep = 35 accounts, +14 new, 0 errors, ~56s.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Files touched
M agents/instagram-agent/live-media.jsM agents/instagram-agent/server.js
Diff
commit 8cfcfe2a9cb03bd7a96bb969c327b6b29c16282c
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Tue Aug 18 14:29:26 2026 -0700
instagram: keep ALL accounts live via cron (not just DW)
- refreshAllAccounts(): serialized, per-account error-isolated sweep of the whole
35-account roster (incremental by default; full+onlyIncomplete for backfill).
- live-media-refresh cron now sweeps ALL accounts hourly (was DW-only), so the
cross-account /calendar stays live for the whole roster.
- new live-media-backfill-sweep cron (daily 04:40): full-backfills up to 5 not-yet-
complete accounts/run as a safety net; no-ops once all complete.
Verified: one-shot incremental sweep = 35 accounts, +14 new, 0 errors, ~56s.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---
agents/instagram-agent/live-media.js | 37 +++++++++++++++++++++++++++++++++++-
agents/instagram-agent/server.js | 26 +++++++++++++++++++++----
2 files changed, 58 insertions(+), 5 deletions(-)
diff --git a/agents/instagram-agent/live-media.js b/agents/instagram-agent/live-media.js
index e127001..cb66ca6 100644
--- a/agents/instagram-agent/live-media.js
+++ b/agents/instagram-agent/live-media.js
@@ -160,6 +160,41 @@ async function refreshLiveMedia({ igUserId, full = false, maxPages = full ? 260
} finally { REFRESH_LOCKS.delete(id); }
}
+/**
+ * Sweep EVERY account in the roster through refreshLiveMedia, serialized (one at a time, with a
+ * small gap) so we stay gentle on the shared Graph token's rate limit and never trip two refreshes
+ * of the same account at once. Per-account errors are captured, not thrown — one bad account never
+ * aborts the sweep. This is what keeps the cross-account calendar LIVE for all accounts, not just DW.
+ * - incremental (default): each account stops early when it hits already-known posts → cheap.
+ * - { full:true }: full history walk (used by the backfill safety-net).
+ * - { onlyIncomplete:true }: skip accounts already marked complete (for the backfill sweep).
+ * - { max }: cap how many accounts to touch this run (drains a big backfill over several runs).
+ */
+async function refreshAllAccounts({ full = false, onlyIncomplete = false, max = 0, delayMs = 400 } = {}) {
+ if (!TOKEN()) return { skipped: 'simulation mode', accounts: 0, added: 0, results: [] };
+ const roster = listAccounts();
+ const results = [];
+ let touched = 0;
+ for (const a of roster) {
+ if (onlyIncomplete) {
+ const c = readCache(a.ig_user_id);
+ if (c && c.complete === true) continue; // already fully backfilled — skip
+ }
+ try {
+ const r = await refreshLiveMedia({ igUserId: a.ig_user_id, full });
+ results.push({ handle: a.handle, added: r.added, scanned: r.scanned, complete: r.complete });
+ } catch (e) {
+ results.push({ handle: a.handle, error: e.message });
+ }
+ touched++;
+ if (max && touched >= max) break;
+ await new Promise((r) => setTimeout(r, delayMs));
+ }
+ const added = results.reduce((s, r) => s + (r.added || 0), 0);
+ const errors = results.filter((r) => r.error).length;
+ return { accounts: results.length, added, errors, results };
+}
+
// ── grouping for the viewer ─────────────────────────────────────────────────
function dayLabel(iso, today) {
const d = new Date(iso);
@@ -243,4 +278,4 @@ function registerLiveRoutes(app, agentName = 'instagram-agent') {
});
}
-module.exports = { registerLiveRoutes, refreshLiveMedia, getLivePosts, listAccounts, readCache, readTombstones };
+module.exports = { registerLiveRoutes, refreshLiveMedia, refreshAllAccounts, getLivePosts, listAccounts, readCache, readTombstones };
diff --git a/agents/instagram-agent/server.js b/agents/instagram-agent/server.js
index 454e9f1..f8ad39d 100644
--- a/agents/instagram-agent/server.js
+++ b/agents/instagram-agent/server.js
@@ -129,18 +129,36 @@ const { app, start, scheduler } = createAgentServer({
},
{
name: 'live-media-refresh',
- schedule: '7 * * * *', // hourly at :07 — pull new posts from the DW feed into the /live cache
+ schedule: '7 * * * *', // hourly at :07 — pull new posts into the /live + /calendar caches
fn: async () => {
if (!liveMode()) return;
try {
- const { refreshLiveMedia } = require('./live-media');
- const r = await refreshLiveMedia({ full: false });
- console.log(`[${AGENT_NAME}] Cron live-media refresh: +${r.added} new (scanned ${r.scanned})`);
+ // Sweep ALL accounts (not just DW) so the cross-account calendar stays LIVE for the
+ // whole roster. Incremental: each account stops early on already-known posts → cheap.
+ const { refreshAllAccounts } = require('./live-media');
+ const r = await refreshAllAccounts({ full: false });
+ console.log(`[${AGENT_NAME}] Cron live-media refresh: +${r.added} new across ${r.accounts} accounts (errors ${r.errors})`);
} catch (err) {
console.error(`[${AGENT_NAME}] Cron live-media refresh error:`, err.message);
}
},
},
+ {
+ name: 'live-media-backfill-sweep',
+ schedule: '40 4 * * *', // daily 04:40 — safety net: fully backfill any account not yet complete
+ fn: async () => {
+ if (!liveMode()) return;
+ try {
+ const { refreshAllAccounts } = require('./live-media');
+ // Only touch accounts still marked incomplete, a few per run, so a big backfill drains
+ // over several nights without hammering the shared Graph token. No-ops once all complete.
+ const r = await refreshAllAccounts({ full: true, onlyIncomplete: true, max: 5, delayMs: 1200 });
+ console.log(`[${AGENT_NAME}] Cron backfill sweep: backfilled ${r.accounts} incomplete account(s), +${r.added} posts (errors ${r.errors})`);
+ } catch (err) {
+ console.error(`[${AGENT_NAME}] Cron backfill sweep error:`, err.message);
+ }
+ },
+ },
{
name: 'report-to-pulse',
schedule: '0 */4 * * *', // every 4 hours
← 835c032 instagram: cross-account post Calendar view (/calendar)
·
back to Norma
·
auto-data-snapshot: 2026-08-18T14:32:35 (1 data files) — age f85f258 →