Seeding nodes lease first, connect for the lease, close when idle
Test and deploy / test (push) Successful in 1m36s
Test and deploy / deploy (push) Successful in 1m58s

A failed NNTP login gives the range back uncounted (no attempt used), and a
node with nothing to lease holds no connection. Replaces log-in-before-lease,
which kept idle connections and logged in again every minute while idle.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Daan MeijerandClaude Opus 5.5 committed 2026-10-05 15:18:38 +02:00
1 parent 70036847cf
commit 3d5cfb2527
4 files changed
+54 -36

No files matched your search

+3 -2
View File
@@ -39,11 +39,12 @@ export default class SeedController {
})
}
/** POST /api/v1/seed/ranges/:id/release { error? } */
/** POST /api/v1/seed/ranges/:id/release { error?, uncounted? } */
async release({ seedNode, params, request, response }: HttpContext) {
const error = request.input('error')
const uncounted = request.input('uncounted') === true
return this.leased(response, async () => {
await SeedOrchestrator.release(seedNode.id, Number(params.id), typeof error === 'string' ? error : undefined)
await SeedOrchestrator.release(seedNode.id, Number(params.id), typeof error === 'string' ? error : undefined, uncounted)
return { ok: true }
})
}
+8 -3
View File
@@ -97,13 +97,18 @@ class SeedOrchestrator {
await db.from('seed_ranges').where('id', rangeId).update({ status: 'done', done_at: new Date(), heartbeat_at: new Date(), error: null })
}
/** A node gives a range back (it failed, or is shutting down); it's queued again unless it failed too often. */
async release(nodeId: number, rangeId: number, error?: string) {
/**
* A node gives a range back (it failed, or is shutting down); it's queued
* again unless it failed too often. `uncounted`: the node never started on
* it (couldn't reach its news server), so the lease doesn't count as an attempt.
*/
async release(nodeId: number, rangeId: number, error?: string, uncounted = false) {
const range = await this.leased(nodeId, rangeId)
const attempts = uncounted ? Math.max(0, range.attempts - 1) : range.attempts
await db
.from('seed_ranges')
.where('id', rangeId)
.update({ status: range.attempts >= MAX_ATTEMPTS ? 'failed' : 'queued', node_id: null, error: error?.slice(0, 2000) ?? null })
.update({ status: attempts >= MAX_ATTEMPTS ? 'failed' : 'queued', node_id: null, attempts, error: error?.slice(0, 2000) ?? null })
}
private async leased(nodeId: number, rangeId: number) {