Pace candidate funnel to send capacity
This commit is contained in:
1 parent
910576921b
commit
70c156e1f7
7 files changed
+113
-13
No files matched your search
@@ -77,10 +77,23 @@ describe('CandidateQueueRepository', () => {
|
||||
duplicateAuthor: 1,
|
||||
previouslyProcessed: 0,
|
||||
previouslyContacted: 0,
|
||||
deferredAtCapacity: 0,
|
||||
});
|
||||
expect(queue.getStats().byStatus.discovered).toBe(2);
|
||||
});
|
||||
|
||||
it('fills only the requested intake deficit and reports untouched posts', () => {
|
||||
const result = queue.enqueue([
|
||||
post('p1', 'alice'),
|
||||
post('p2', 'bob'),
|
||||
post('p3', 'carol'),
|
||||
], 'image', 1, 1_000, 2);
|
||||
|
||||
expect(result.discovered).toBe(2);
|
||||
expect(result.deferredAtCapacity).toBe(1);
|
||||
expect(queue.countActive()).toBe(2);
|
||||
});
|
||||
|
||||
it('excludes posts and recipients already handled anywhere', () => {
|
||||
db.prepare(`
|
||||
INSERT INTO processed_posts (account_id, id, subreddit, author, title, processed_at)
|
||||
|
||||
+31
-1
@@ -1,5 +1,9 @@
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
import { currentHourlySendCount, startNonOverlappingSchedule } from '../src/main-loop.js';
|
||||
import {
|
||||
calculateCandidateFunnelTarget,
|
||||
currentHourlySendCount,
|
||||
startNonOverlappingSchedule,
|
||||
} from '../src/main-loop.js';
|
||||
|
||||
describe('startNonOverlappingSchedule', () => {
|
||||
it('does not begin a second response check until the prior check settles', async () => {
|
||||
@@ -43,3 +47,29 @@ describe('currentHourlySendCount', () => {
|
||||
expect(currentHourlySendCount({ getStats: () => ({ messagesThisHour: 1 }) })).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('calculateCandidateFunnelTarget', () => {
|
||||
it('tracks remaining outbound capacity instead of growing to a fixed backlog', () => {
|
||||
expect(calculateCandidateFunnelTarget(
|
||||
[{ messagesRemaining: 3 }, { messagesRemaining: 5 }],
|
||||
{ maxReadyCandidates: 25, recentWindowMinutes: 60, minDelayBetweenMessagesMs: 300_000 },
|
||||
)).toBe(8);
|
||||
});
|
||||
|
||||
it('retains the configured ceiling and caps capacity by the freshness window', () => {
|
||||
expect(calculateCandidateFunnelTarget(
|
||||
[{ messagesRemaining: 100 }, { messagesRemaining: 100 }],
|
||||
{ maxReadyCandidates: 25, recentWindowMinutes: 30, minDelayBetweenMessagesMs: 300_000 },
|
||||
)).toBe(12);
|
||||
});
|
||||
|
||||
it('stops growing inventory when no running account can send', () => {
|
||||
const options = {
|
||||
maxReadyCandidates: 25,
|
||||
recentWindowMinutes: 60,
|
||||
minDelayBetweenMessagesMs: 300_000,
|
||||
};
|
||||
expect(calculateCandidateFunnelTarget([], options)).toBe(0);
|
||||
expect(calculateCandidateFunnelTarget([{ messagesRemaining: 0 }], options)).toBe(0);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user