Pause suspended Reddit accounts

This commit is contained in:
jjbrunton committed 2026-08-14 16:00:37 +01:00
1 parent 94049ed9c4
commit 7d039265e7
21 files changed
+368 -26

No files matched your search

+20 -1
View File
@@ -38,6 +38,7 @@ import type { RecipientAccountStatusService } from './recipient-account-status.j
import type { AccountEstablishmentService } from './account-establishment.js';
import type { AccountGrowthService } from './account-growth.js';
import type { AccountBrowsingSimulationService } from './account-browsing-simulation.js';
import type { AccountSuspensionService } from './account-suspension.js';
import type { ProcessedPost, ProcessResult } from './processor.js';
import type { ConversationEventRepository } from '../database/conversation-event-repository.js';
import type { ConversationLearningRepository } from '../database/conversation-learning-repository.js';
@@ -91,6 +92,8 @@ export interface RedditAccountRuntimeResources {
mediaSyncService: MediaSyncService;
recipientAccountStatusService: RecipientAccountStatusService;
establishmentService: AccountEstablishmentService;
/** Present in concrete runtimes; optional for narrow lifecycle test fixtures. */
suspensionService?: AccountSuspensionService;
/**
* Comment-based account growth. Optional because a runtime is fully
* functional without it, and it is disabled per account by default.
@@ -107,6 +110,8 @@ export interface RedditAccountRuntimeLifecycle {
start(): void | Promise<void>;
/** Stop and await this account's schedules/loop, then close its browser. */
stop(): void | Promise<void>;
/** Immediately halt account work after a definitive suspension signal. */
pause?(reason: string): void;
/** Process a post assigned by the shared discovery scheduler. */
dispatchPost?(post: RedditPost, signal?: AbortSignal): Promise<void>;
preparePost?(post: RedditPost, signal?: AbortSignal): Promise<ProcessResult>;
@@ -123,6 +128,7 @@ export type RedditAccountRuntimeState =
| 'starting'
| 'running'
| 'stopping'
| 'paused'
| 'stopped'
| 'failed';
@@ -197,6 +203,17 @@ export class RedditAccountRuntime {
});
}
/**
* Suspension can be discovered by work that this runtime is currently
* awaiting. Keep this synchronous so it cannot wait on its own loop.
*/
pause(reason: string): void {
if (this.state === 'stopped' || this.state === 'failed') return;
this.failure = reason;
this.state = 'paused';
this.lifecycle.pause?.(reason);
}
snapshot(): RedditAccountRuntimeSnapshot {
return {
accountId: this.session.accountId,
@@ -294,7 +311,9 @@ export class RedditAccountRuntimeManager {
async startEnabled(): Promise<RedditAccountRuntimeManagerSnapshot> {
const enabled = this.accounts.listPublic().filter(isEnabledAccount);
await Promise.all(enabled.map((account) => this.start(account.accountId)));
// A broken or suspended session belongs to one account. Do not prevent
// other verified accounts from starting because of it.
await Promise.allSettled(enabled.map((account) => this.start(account.accountId)));
return this.snapshot();
}