NNTP shares: the account's connections shared by priority
The coordinator (38) and the prober (8) had a fixed split; with history paused the coordinator's stood idle while the prober's were its limit. nntp_shares: each process syncs every 15 s (priority, minimum, what it could use, what it has open) and gets what it may open: minimums first, then by priority what each wants, growing only into connections the others closed or gave up. The pool's size and the prober's lanes follow the grant; the coordinator doubles its want while work waits for a connection, else asks for its peak in use and a margin; the prober wants its maximum unless the queue is dry. Claims scale with the lanes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
7eba53043a
commit
39480c486f
10 files changed
+373
-75
No files matched your search
@@ -0,0 +1,53 @@
|
||||
import { test } from '@japa/runner'
|
||||
import db from '@adonisjs/lucid/services/db'
|
||||
import testUtils from '@adonisjs/core/services/test_utils'
|
||||
import coordinatorConfig from '#config/coordinator'
|
||||
import { grant, targets, NntpShare } from '#services/nntp_shares'
|
||||
|
||||
test.group('NNTP shares', (group) => {
|
||||
group.each.setup(() => testUtils.db().withGlobalTransaction())
|
||||
|
||||
test('targets: minimums first, then by priority what each wants', ({ assert }) => {
|
||||
const coordinator = { name: 'coordinator', priority: 2, min: 8, want: 38, open: 0 }
|
||||
const prober = { name: 'prober', priority: 1, min: 2, want: 40, open: 0 }
|
||||
// History running: the coordinator all it wants, the prober the rest.
|
||||
assert.deepEqual(Object.fromEntries(targets(45, [prober, coordinator])), { coordinator: 38, prober: 7 })
|
||||
// History paused: the coordinator its minimum (or what it uses), the prober the rest.
|
||||
assert.deepEqual(Object.fromEntries(targets(45, [prober, { ...coordinator, want: 8 }])), { coordinator: 8, prober: 37 })
|
||||
// Wanting more than its minimum doesn't take another's minimum.
|
||||
assert.deepEqual(Object.fromEntries(targets(45, [prober, { ...coordinator, want: 60 }])), { coordinator: 43, prober: 2 })
|
||||
})
|
||||
|
||||
test('grant: growing only into connections the others closed or gave up', ({ assert }) => {
|
||||
const prober = { name: 'prober', priority: 1, min: 2, want: 40, open: 37, granted: 37 }
|
||||
const coordinator = { name: 'coordinator', priority: 2, min: 8, want: 38, open: 8 }
|
||||
// History came back: the prober still holds 37, the coordinator keeps its 8 for now.
|
||||
assert.equal(grant(45, coordinator, [prober]), 8)
|
||||
// The prober syncs: its target is 7, its grant goes down at once.
|
||||
assert.equal(grant(45, { ...prober, open: 37 }, [{ ...coordinator, granted: 8 }]), 7)
|
||||
// Its connections not closed yet: still held.
|
||||
assert.equal(grant(45, coordinator, [{ ...prober, granted: 7, open: 30 }]), 15)
|
||||
// Closed: the coordinator gets all it wants.
|
||||
assert.equal(grant(45, coordinator, [{ ...prober, granted: 7, open: 7 }]), 38)
|
||||
})
|
||||
|
||||
test('sync: each process its row; a process gone (no heartbeat) holds nothing', async ({ assert }) => {
|
||||
const total = coordinatorConfig.nntpShares.total
|
||||
const coordinator = new NntpShare('coordinator', 2, 8, 38)
|
||||
const prober = new NntpShare('prober', 1, 2, total)
|
||||
assert.equal(await coordinator.sync(8, 0), 8)
|
||||
assert.equal(await prober.sync(total, 0), total - 8)
|
||||
// The coordinator wants all: the prober holds its grant until it has synced and closed them.
|
||||
assert.equal(await coordinator.sync(38, 8), 8)
|
||||
assert.equal(await prober.sync(total, total - 8), total - 38)
|
||||
assert.equal(await coordinator.sync(38, 8), 8)
|
||||
assert.equal(await prober.sync(total, total - 38), total - 38)
|
||||
assert.equal(await coordinator.sync(38, 8), 38)
|
||||
|
||||
// The prober's process died: after a minute without a sync its share is free.
|
||||
await db.from('nntp_shares').where('name', 'prober').update({ open: total, granted: total, heartbeat_at: new Date(Date.now() - 120_000) })
|
||||
assert.equal(await coordinator.sync(38, 38), 38)
|
||||
await coordinator.leave()
|
||||
assert.equal(await prober.sync(total, 0), total)
|
||||
})
|
||||
})
|
||||
Reference in new issue
Block a user