diff --git a/src/config.jsonc b/src/config.jsonc index 8ce9961..4c53db6 100644 --- a/src/config.jsonc +++ b/src/config.jsonc @@ -21,7 +21,7 @@ "parallel": false, "runOnZeroPoints": false, "clusters": 1, - "passesPerRun": 1 // Number of times to run through all accounts (set to 3 to run 3 times even if already completed) + "passesPerRun": 3 // Number of times to run through all accounts (set to 3 to run 3 times even if already completed) }, "jobState": { "enabled": true, diff --git a/src/index.ts b/src/index.ts index bd9e792..13cb76d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -225,7 +225,17 @@ export class MicrosoftRewardsBot { this.runWorker() } } else { - await this.runTasks(this.accounts) + const passes = this.config.passesPerRun ?? 1 + for (let pass = 1; pass <= passes; pass++) { + if (passes > 1) { + log('main', 'MAIN', `Starting pass ${pass}/${passes}`) + } + await this.runTasks(this.accounts) + if (pass < passes) { + log('main', 'MAIN', `Completed pass ${pass}/${passes}. Waiting before next pass...`) + await this.utils.wait(60000) // 1 minute between passes + } + } } } @@ -515,7 +525,17 @@ export class MicrosoftRewardsBot { log('main', 'MAIN-WORKER', `Worker ${process.pid} spawned`) // Receive the chunk of accounts from the master ;(process as unknown as { on: (ev: 'message', cb: (m: { chunk: Account[] }) => void) => void }).on('message', async ({ chunk }: { chunk: Account[] }) => { - await this.runTasks(chunk) + const passes = this.config.passesPerRun ?? 1 + for (let pass = 1; pass <= passes; pass++) { + if (passes > 1) { + log('main', 'MAIN-WORKER', `Starting pass ${pass}/${passes}`) + } + await this.runTasks(chunk) + if (pass < passes) { + log('main', 'MAIN-WORKER', `Completed pass ${pass}/${passes}. Waiting before next pass...`) + await this.utils.wait(60000) // 1 minute between passes + } + } }) } diff --git a/src/util/StartupValidator.ts b/src/util/StartupValidator.ts index be0fd47..20e2752 100644 --- a/src/util/StartupValidator.ts +++ b/src/util/StartupValidator.ts @@ -34,6 +34,7 @@ export class StartupValidator { this.validateBrowserSettings(config) this.validateNetworkSettings(config) this.validateWorkerSettings(config) + this.validateExecutionSettings(config) this.validateSearchSettings(config) this.validateHumanizationSettings(config) this.validateSecuritySettings(config) @@ -484,6 +485,58 @@ export class StartupValidator { } } + private validateExecutionSettings(config: Config): void { + // Validate passesPerRun + const passes = config.passesPerRun ?? 1 + + if (passes < 1) { + this.addError( + 'execution', + 'passesPerRun must be at least 1', + 'Set passesPerRun to 1 or higher in config.jsonc', + undefined, + true + ) + } + + if (passes > 5) { + this.addWarning( + 'execution', + `passesPerRun is set to ${passes} (very high)`, + 'Running multiple passes per day may trigger Microsoft detection. Recommended: 1-2 passes max', + 'docs/config-reference.md' + ) + } + + if (passes > 1) { + this.addWarning( + 'execution', + 'passesPerRun > 1: Job-state skip is disabled', + 'All accounts will run on every pass, even if already completed. This is intentional for multiple passes.', + 'docs/jobstate.md' + ) + } + + // Validate clusters + if (config.clusters < 1) { + this.addError( + 'execution', + 'clusters must be at least 1', + 'Set clusters to 1 or higher in config.jsonc', + undefined, + true + ) + } + + if (config.clusters > 10) { + this.addWarning( + 'execution', + `clusters is set to ${config.clusters} (very high)`, + 'Too many clusters may cause resource exhaustion. Recommended: 1-4 clusters' + ) + } + } + private validateSearchSettings(config: Config): void { const search = config.searchSettings