Bots Inventory¶
In addition to the 57 job_*.js files (see jobs-inventory.md), there are 6 standalone files at the repo root that play a hybrid role: each is library-like (exports functions used by routes/routes.js) and runs its own cron.schedule(...) at the top. They are colloquially "bots".
Inventory¶
| File | LoC (approx) | Cron | Purpose |
|---|---|---|---|
content_generation_bot.js |
6721 bytes | (cron schedule TBD) | Topic-driven AI content generation: pulls tTopics, iterates tDefaultCategories, generates copy via OpenAI. Exports getmodels, getmodelcopies. |
post_image_generation1_bot.js |
5006 bytes | TBD | Image generation worker |
FAQsbot.js |
11642 bytes | */60 * * * * (hourly) |
OpenAI-driven FAQ generation; getContentFromText() |
quizbot.js |
11255 bytes | */60 * * * * (hourly) |
OpenAI-driven quiz generation |
quotesbot.js |
10685 bytes | TBD | OpenAI-driven quote generation |
trendsbot.js |
10797 bytes | TBD | OpenAI-driven trends-driven content |
Pattern¶
var conf = require("./conf");
var cron = require("node-cron");
const mysql = require("sync-mysql");
const OpenAI = require('openai');
const openai = new OpenAI({ apiKey: conf.OPENAI_API_KEY });
const con = new mysql({ /* connection */ });
let isOnProcess = false;
cron.schedule("...", () => { getContentFromText(); });
async function getContentFromText() {
if (!isOnProcess) {
isOnProcess = true;
// fetch a row from a queue table
// call OpenAI
// write the result back to DB
isOnProcess = false;
}
}
module.exports = { fnA, fnB }; // some bots export functions too
Why the "bot" vs "job" distinction?¶
In practice, these files behave just like jobs (cron-scheduled, sync-mysql, AI-calling). The bot naming likely reflects the work being more "AI generation" than "queue processing". From an operational view, treat them as jobs.
Risk: combined OpenAI rate-limit hits¶
All 6 bots run on */60 * * * * (hourly) — they all wake at the top of the hour and burst OpenAI calls. If they each issue 10-50 calls per tick, the combined rate at :00 could exceed OpenAI's per-account rate limit.
Recommendation: stagger the schedules. E.g., 15 * * * *, 30 * * * *, 45 * * * * for the four hourly bots so they don't dogpile.
Risk: shared isOnProcess semantics¶
Each file's isOnProcess is in-process. If a bot's previous tick is still running when the next tick fires, the new one is skipped. What happens if the work takes longer than the cron interval? The bot is effectively serialised. For 60-minute intervals this is unlikely, but jobs running every 1 minute (some) will start dropping ticks when work runs slow.
Imports into the main app¶
routes/routes.js line 19:
This means starting server.js also kick-starts content_generation_bot.js's cron (because module-level cron.schedule(...) runs at require-time). The main app process therefore runs the bot's cron in addition to whatever PM2 processes the bot separately. If pm2 start content_generation_bot.js is also running, you have two cron handlers for the same job in parallel — they trip each other's isOnProcess flag (or don't, since they're different processes).
Verify: check the deploy's PM2 manifest; if content_generation_bot.js is started as its own PM2 process, the import inside routes/routes.js is causing duplicate cron scheduling. Fix by either (a) not importing the cron-bearing bot file from routes/routes.js (split functions out into a library file with no cron), or (b) using a IS_WORKER env flag to no-op the cron in non-worker processes.
Recommendations¶
| ID | Recommendation | Effort |
|---|---|---|
| B-1 | Split each bot into *_bot.js (cron-only) and *_lib.js (functions imported by routes) |
Medium |
| B-2 | Add a IS_WORKER env flag so bots' crons no-op when started inside the main server process |
Small |
| B-3 | Stagger cron schedules to spread OpenAI calls | Trivial |
| B-4 | Add OpenAI usage tracking per bot (cost visibility) | Medium |
| B-5 | Move bots' sync-mysql to mysql2/promise |
Medium |
| B-6 | Centralise prompt templates in helper/prompts/ instead of inline literals |
Medium |