This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
@@ -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() },
|
||||
)
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user