data growth features
Build Images and Deploy / Update-PROD-Stack (push) Successful in 1m19s

This commit is contained in:
2026-03-19 01:25:22 -04:00
parent c78045e2b9
commit 589763fa44
4 changed files with 46 additions and 3 deletions
+3
View File
@@ -21,6 +21,9 @@ PRICE_UPDATE_INTERVAL_MINUTES=60
HASHTAG_ACTIVE_HOURS=24
# Max pagination pages to fetch when counting posts (default: 5 = up to 200 posts)
MAX_PAGES_PER_HASHTAG=5
# Price history retention: days to keep for active hashtags, hours for inactive ones
PRICE_HISTORY_ACTIVE_DAYS=7
PRICE_HISTORY_INACTIVE_HOURS=24
# Initial admin user — only used by `npm run db:seed`, not the running app.
# Pass these at seed time: docker exec -e ADMIN_USERNAME=x -e ADMIN_PASSWORD=y <container> npm run db:seed
+1
View File
@@ -36,6 +36,7 @@ async function fetchPage(tag: string, maxId?: string): Promise<TimelineResult> {
if (!instance) throw new Error('MASTODON_INSTANCE is not configured')
let url = `${instance}/api/v1/timelines/tag/${encodeURIComponent(tag)}`
// ?limit=50 was here but it seemed too aggressive. Default is 20 which feels more balanced for pricing purposes and reduces risk of hitting rate limits on very active tags.
if (maxId) url += `&max_id=${maxId}`
const headers: HeadersInit = { Accept: 'application/json' }
+40 -1
View File
@@ -164,7 +164,12 @@ const priceWorker = new Worker(
)
/**
* Daily maintenance worker — awards research points based on balance milestones.
* Daily maintenance worker — awards research points based on balance milestones,
* and prunes old price history to control data growth.
*
* Retention policy:
* - Active hashtags: keep last 7 days
* - Inactive hashtags: keep last 24 hours
*/
const maintenanceWorker = new Worker(
'hashex-maintenance',
@@ -185,6 +190,40 @@ const maintenanceWorker = new Worker(
}
console.log(`[maintenance] awarded research points to ${users.length} users`)
// ── Price history pruning ──────────────────────────────────────────────
const now = new Date()
const activeDays = parseInt(process.env.PRICE_HISTORY_ACTIVE_DAYS ?? '7', 10)
const inactiveHours = parseInt(process.env.PRICE_HISTORY_INACTIVE_HOURS ?? '24', 10)
const cutoff7d = new Date(now.getTime() - activeDays * 24 * 60 * 60 * 1000)
const cutoff24h = new Date(now.getTime() - inactiveHours * 60 * 60 * 1000)
// Active hashtags: drop history older than 7 days
const activeIds = (
await prisma.hashtag.findMany({ where: { isActive: true }, select: { id: true } })
).map((h) => h.id)
const deletedActive = activeIds.length > 0
? await prisma.priceHistory.deleteMany({
where: { hashtagId: { in: activeIds }, recordedAt: { lt: cutoff7d } },
})
: { count: 0 }
// Inactive hashtags: drop history older than 24 hours
const inactiveIds = (
await prisma.hashtag.findMany({ where: { isActive: false }, select: { id: true } })
).map((h) => h.id)
const deletedInactive = inactiveIds.length > 0
? await prisma.priceHistory.deleteMany({
where: { hashtagId: { in: inactiveIds }, recordedAt: { lt: cutoff24h } },
})
: { count: 0 }
console.log(
`[maintenance] pruned price history — active: ${deletedActive.count} rows removed (>${activeDays}d), ` +
`inactive: ${deletedInactive.count} rows removed (>${inactiveHours}h)`,
)
},
{ connection: redisOpts() },
)
+1 -1
View File
File diff suppressed because one or more lines are too long