This commit is contained in:
@@ -21,6 +21,9 @@ PRICE_UPDATE_INTERVAL_MINUTES=60
|
|||||||
HASHTAG_ACTIVE_HOURS=24
|
HASHTAG_ACTIVE_HOURS=24
|
||||||
# Max pagination pages to fetch when counting posts (default: 5 = up to 200 posts)
|
# Max pagination pages to fetch when counting posts (default: 5 = up to 200 posts)
|
||||||
MAX_PAGES_PER_HASHTAG=5
|
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.
|
# 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
|
# 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')
|
if (!instance) throw new Error('MASTODON_INSTANCE is not configured')
|
||||||
|
|
||||||
let url = `${instance}/api/v1/timelines/tag/${encodeURIComponent(tag)}`
|
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}`
|
if (maxId) url += `&max_id=${maxId}`
|
||||||
|
|
||||||
const headers: HeadersInit = { Accept: 'application/json' }
|
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(
|
const maintenanceWorker = new Worker(
|
||||||
'hashex-maintenance',
|
'hashex-maintenance',
|
||||||
@@ -185,6 +190,40 @@ const maintenanceWorker = new Worker(
|
|||||||
}
|
}
|
||||||
|
|
||||||
console.log(`[maintenance] awarded research points to ${users.length} users`)
|
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() },
|
{ connection: redisOpts() },
|
||||||
)
|
)
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user