Remove Redis client presence

This commit is contained in:
Ben
2026-06-20 16:03:34 -04:00
parent cd0cb9bfe0
commit d1fb186e5d
20 changed files with 111 additions and 613 deletions
+3 -17
View File
@@ -41,7 +41,7 @@ describe('StratumV1Client', () => {
let configService: ConfigService;
let addressSettings: AddressSettingsService;
let shareAccountingService: { recordAcceptedShare: jest.Mock };
let redisMessagingService: { setClientPresence: jest.Mock; removeClientPresence: jest.Mock };
let redisMessagingService: Record<string, never>;
let client: StratumV1Client;
@@ -80,6 +80,7 @@ describe('StratumV1Client', () => {
}),
connectedClientCount: jest.fn(async () => clients.size),
updateBestDifficultyIfHigher: jest.fn().mockResolvedValue({ affected: 1 }),
updateHashRate: jest.fn().mockResolvedValue(undefined),
} as any;
configService = {
@@ -132,10 +133,7 @@ describe('StratumV1Client', () => {
shareAccountingService = {
recordAcceptedShare: jest.fn().mockResolvedValue(undefined),
};
redisMessagingService = {
setClientPresence: jest.fn().mockResolvedValue(undefined),
removeClientPresence: jest.fn().mockResolvedValue(undefined),
};
redisMessagingService = {};
client = new StratumV1Client(
@@ -185,11 +183,6 @@ describe('StratumV1Client', () => {
await Promise.all([client.destroy(), client.destroy()]);
expect(redisMessagingService.removeClientPresence).toHaveBeenCalledTimes(1);
expect(redisMessagingService.removeClientPresence).toHaveBeenCalledWith(
'00000000-0000-4000-8000-000000000001',
'tb1qcleanup',
);
expect(clientService.delete).toHaveBeenCalledTimes(1);
expect(clientService.delete).toHaveBeenCalledWith('00000000-0000-4000-8000-000000000001');
expect(unsubscribe).toHaveBeenCalledTimes(1);
@@ -415,13 +408,6 @@ describe('StratumV1Client', () => {
creditedDifficulty: 0,
isBlockCandidate: false,
}));
expect(redisMessagingService.setClientPresence).toHaveBeenCalledWith(expect.objectContaining({
address: 'tb1qumezefzdeqqwn5zfvgdrhxjzc5ylr39uhuxcz4',
clientName: 'bitaxe3',
sessionId: MockRecording1.EXTRA_NONCE,
}));
});
it('should use the header-only fast path for non-block submissions', async () => {
-28
View File
@@ -124,8 +124,6 @@ export class StratumV1Client {
if (this.clientEntity?.id) {
const clientId = this.clientEntity.id;
const address = this.clientEntity.address;
await this.redisMessagingService?.removeClientPresence(clientId, address);
await this.clientService.delete(clientId);
}
}
@@ -527,36 +525,12 @@ export class StratumV1Client {
payoutMode: this.payoutMode,
bestDifficulty: 0
});
await this.updateClientPresence(new Date());
})();
}
await this.creatingEntity;
}
private async updateClientPresence(lastSeen: Date): Promise<void> {
if (this.clientEntity == null) {
return;
}
try {
await this.redisMessagingService?.setClientPresence({
clientId: this.clientEntity.id,
address: this.clientEntity.address,
clientName: this.clientEntity.clientName,
sessionId: this.clientEntity.sessionId,
payoutMode: this.payoutMode,
userAgent: this.clientEntity.userAgent,
startTime: new Date(this.clientEntity.startTime).toISOString(),
lastSeen: lastSeen.toISOString(),
hashRate: this.statistics?.hashRate ?? 0,
bestDifficulty: Number(this.clientEntity.bestDifficulty ?? 0),
});
} catch (error) {
console.error(`Failed to update SV1 client presence: ${error.message}`);
}
}
private async handleMiningSubmission(submission: MiningSubmitMessage) {
const job = this.stratumV1JobsService.getJobById(submission.jobId);
@@ -707,7 +681,6 @@ export class StratumV1Client {
this.clientEntity.updatedAt = now;
this.clientEntity.hashRate = this.statistics.hashRate;
await this.persistClientHashRate(now);
await this.updateClientPresence(now);
} catch (e) {
console.log(e);
@@ -717,7 +690,6 @@ export class StratumV1Client {
await this.clientService.updateBestDifficultyIfHigher(this.clientEntity.id, submissionDifficulty);
this.clientEntity.bestDifficulty = submissionDifficulty;
await this.addressSettingsService.updateBestDifficultyIfHigher(this.clientAuthorization.address, submissionDifficulty, this.clientEntity.userAgent);
await this.updateClientPresence(new Date());
}
+7 -11
View File
@@ -301,8 +301,8 @@ describe('StratumV2Client extended channels', () => {
expect((client as any).channels.get(1).extendedJobs.has(100)).toBe(false);
});
it('records accepted SV2 shares before presence updates', async () => {
const { client, shareAccountingService, redisMessagingService, jobTemplate } = await createClient();
it('records accepted SV2 shares and persists DB hashrate', async () => {
const { client, clientService, shareAccountingService, jobTemplate } = await createClient();
(client as any).address = 'tb1qumezefzdeqqwn5zfvgdrhxjzc5ylr39uhuxcz4';
(client as any).workerName = 'worker';
(client as any).sessionId = 'sv2-session';
@@ -333,10 +333,6 @@ describe('StratumV2Client extended channels', () => {
nonce: 123,
extraNonce2: 'c708000000000000',
}));
const accountingCallOrder = shareAccountingService.recordAcceptedShare.mock.invocationCallOrder[0];
const postAccountingPresenceUpdates = redisMessagingService.setClientPresence.mock.invocationCallOrder
.filter(callOrder => callOrder > accountingCallOrder);
expect(postAccountingPresenceUpdates.length).toBeGreaterThan(0);
});
it('does not submit a block when only the reported SV2 difficulty is huge', async () => {
@@ -422,11 +418,12 @@ describe('StratumV2Client extended channels', () => {
client: StratumV2Client;
sentFrames: any[];
bitcoinRpcService: { SUBMIT_BLOCK: jest.Mock };
clientService: { updateHashRate: jest.Mock };
blocksService: { save: jest.Mock };
notificationService: { notifySubscribersBlockFound: jest.Mock };
addressSettingsService: { resetBestDifficultyAndShares: jest.Mock; updateBestDifficultyIfHigher: jest.Mock };
shareAccountingService: { recordAcceptedShare: jest.Mock };
redisMessagingService: { setClientPresence: jest.Mock; removeClientPresence: jest.Mock };
redisMessagingService: Record<string, never>;
jobTemplate: any;
}> {
const blockTemplate$ = new BehaviorSubject(MockRecording1.BLOCK_TEMPLATE);
@@ -469,6 +466,7 @@ describe('StratumV2Client extended channels', () => {
insert: jest.fn().mockResolvedValue(clientEntity),
delete: jest.fn().mockResolvedValue(undefined),
updateBestDifficultyIfHigher: jest.fn().mockResolvedValue(undefined),
updateHashRate: jest.fn().mockResolvedValue(undefined),
};
const shareAccountingService = {
recordAcceptedShare: jest.fn().mockResolvedValue(undefined),
@@ -479,10 +477,7 @@ describe('StratumV2Client extended channels', () => {
const blocksService = {
save: jest.fn().mockResolvedValue(undefined),
};
const redisMessagingService = {
setClientPresence: jest.fn().mockResolvedValue(undefined),
removeClientPresence: jest.fn().mockResolvedValue(undefined),
};
const redisMessagingService = {};
const addressSettingsService = {
resetBestDifficultyAndShares: jest.fn().mockResolvedValue(undefined),
updateBestDifficultyIfHigher: jest.fn().mockResolvedValue(undefined),
@@ -548,6 +543,7 @@ describe('StratumV2Client extended channels', () => {
client,
sentFrames,
bitcoinRpcService,
clientService,
blocksService,
notificationService,
addressSettingsService,
-27
View File
@@ -191,7 +191,6 @@ export class StratumV2Client {
}
this.channels.clear();
if (this.clientEntity?.id != null) {
await this.redisMessagingService?.removeClientPresence(this.clientEntity.id, this.clientEntity.address);
await this.clientService.delete(this.clientEntity.id);
}
}
@@ -937,7 +936,6 @@ export class StratumV2Client {
this.clientEntity.updatedAt = now;
this.clientEntity.hashRate = this.statistics.hashRate;
await this.persistClientHashRate(now);
await this.updateClientPresence(now);
if (submissionDifficulty > this.clientEntity.bestDifficulty) {
await this.clientService.updateBestDifficultyIfHigher(this.clientEntity.id, submissionDifficulty);
@@ -947,7 +945,6 @@ export class StratumV2Client {
submissionDifficulty,
this.userAgent,
);
await this.updateClientPresence(new Date());
}
}
@@ -1316,36 +1313,12 @@ export class StratumV2Client {
payoutMode: this.payoutMode,
bestDifficulty: 0,
});
await this.updateClientPresence(new Date());
})();
}
await this.creatingEntity;
}
private async updateClientPresence(lastSeen: Date): Promise<void> {
if (this.clientEntity == null) {
return;
}
try {
await this.redisMessagingService?.setClientPresence({
clientId: this.clientEntity.id,
address: this.clientEntity.address,
clientName: this.clientEntity.clientName,
sessionId: this.clientEntity.sessionId,
payoutMode: this.payoutMode,
userAgent: this.clientEntity.userAgent,
startTime: new Date(this.clientEntity.startTime).toISOString(),
lastSeen: lastSeen.toISOString(),
hashRate: this.statistics.hashRate,
bestDifficulty: Number(this.clientEntity.bestDifficulty ?? 0),
});
} catch (error) {
console.error(`Failed to update SV2 client presence: ${error.message}`);
}
}
private async persistClientHashRate(now: Date): Promise<void> {
if (this.clientEntity?.id == null) {
return;