mirror of
https://github.com/LightZirconite/Microsoft-Rewards-Bot.git
synced 2026-01-11 09:46:16 +00:00
Cluster issue fix
This commit is contained in:
48
src/index.ts
48
src/index.ts
@@ -206,8 +206,23 @@ export class MicrosoftRewardsBot {
|
|||||||
if (this.config.clusters > 1) {
|
if (this.config.clusters > 1) {
|
||||||
if (cluster.isPrimary) {
|
if (cluster.isPrimary) {
|
||||||
this.runMaster()
|
this.runMaster()
|
||||||
|
} else if (cluster.worker) {
|
||||||
|
await this.runWorker()
|
||||||
} else {
|
} else {
|
||||||
this.runWorker()
|
// Neither primary nor worker - something's wrong with clustering
|
||||||
|
log('main', 'MAIN', `ERROR: Cluster mode failed - neither primary nor worker! Falling back to single-process mode.`, 'error')
|
||||||
|
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, pass, passes)
|
||||||
|
if (pass < passes) {
|
||||||
|
log('main', 'MAIN', `Completed pass ${pass}/${passes}. Waiting before next pass...`)
|
||||||
|
await this.utils.wait(TIMEOUTS.ONE_MINUTE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const passes = this.config.passesPerRun ?? 1
|
const passes = this.config.passesPerRun ?? 1
|
||||||
@@ -301,6 +316,8 @@ export class MicrosoftRewardsBot {
|
|||||||
// FIXED: Proper type checking before calling send
|
// FIXED: Proper type checking before calling send
|
||||||
if (worker.send && typeof worker.send === 'function') {
|
if (worker.send && typeof worker.send === 'function') {
|
||||||
worker.send({ chunk })
|
worker.send({ chunk })
|
||||||
|
} else {
|
||||||
|
log('main', 'MAIN-PRIMARY', `ERROR: Worker ${i} does not have a send function!`, 'error')
|
||||||
}
|
}
|
||||||
worker.on('message', (msg: unknown) => {
|
worker.on('message', (msg: unknown) => {
|
||||||
// IMPROVED: Using type-safe interface and type guard
|
// IMPROVED: Using type-safe interface and type guard
|
||||||
@@ -360,10 +377,23 @@ export class MicrosoftRewardsBot {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private runWorker() {
|
private async runWorker() {
|
||||||
log('main', 'MAIN-WORKER', `Worker ${process.pid} spawned`)
|
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[] }) => {
|
// Wait for chunk (either already received during init, or will arrive soon)
|
||||||
|
const chunk = await new Promise<Account[]>((resolve) => {
|
||||||
|
if ((global as any).__workerChunk) {
|
||||||
|
resolve((global as any).__workerChunk)
|
||||||
|
} else {
|
||||||
|
(process as unknown as { on: (ev: 'message', cb: (m: { chunk: Account[] }) => void) => void }).on('message', ({ chunk: c }: { chunk: Account[] }) => resolve(c))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!chunk || chunk.length === 0) {
|
||||||
|
log('main', 'MAIN-WORKER', `ERROR: Worker ${process.pid} received empty or undefined chunk!`, 'error')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const passes = this.config.passesPerRun ?? 1
|
const passes = this.config.passesPerRun ?? 1
|
||||||
for (let pass = 1; pass <= passes; pass++) {
|
for (let pass = 1; pass <= passes; pass++) {
|
||||||
if (passes > 1) {
|
if (passes > 1) {
|
||||||
@@ -375,7 +405,6 @@ export class MicrosoftRewardsBot {
|
|||||||
await this.utils.wait(TIMEOUTS.ONE_MINUTE)
|
await this.utils.wait(TIMEOUTS.ONE_MINUTE)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async runTasks(accounts: Account[], currentPass: number = 1, totalPasses: number = 1) {
|
private async runTasks(accounts: Account[], currentPass: number = 1, totalPasses: number = 1) {
|
||||||
@@ -872,6 +901,15 @@ const shortErr = shortErrorMessage
|
|||||||
const formatFullError = formatDetailedError
|
const formatFullError = formatDetailedError
|
||||||
|
|
||||||
async function main(): Promise<void> {
|
async function main(): Promise<void> {
|
||||||
|
// FIX: Set up message listener early to prevent race condition
|
||||||
|
// Workers initialize for ~2 seconds before reaching runWorker(), so messages
|
||||||
|
// sent by primary during initialization would be lost without this early listener
|
||||||
|
if (!cluster.isPrimary && cluster.worker) {
|
||||||
|
(process as unknown as { on: (ev: 'message', cb: (m: { chunk: Account[] }) => void) => void }).on('message', ({ chunk }: { chunk: Account[] }) => {
|
||||||
|
(global as any).__workerChunk = chunk
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// Check for dashboard mode flag (standalone dashboard)
|
// Check for dashboard mode flag (standalone dashboard)
|
||||||
if (process.argv.includes('-dashboard')) {
|
if (process.argv.includes('-dashboard')) {
|
||||||
const { startDashboardServer } = await import('./dashboard/server')
|
const { startDashboardServer } = await import('./dashboard/server')
|
||||||
|
|||||||
Reference in New Issue
Block a user