mirror of
https://github.com/status-im/js-waku.git
synced 2025-02-23 18:38:11 +00:00
feat!: lighten retry logic for LightPush (#2182)
* feat: lighten retry logic for LightPush * update tests * remove base protocol sdk from light push, add unit tests for light push * remove replaced test * ensure numPeersToUse is respected * skip tests
This commit is contained in:
parent
19a5d29aa7
commit
4049123f14
@ -1,5 +1,4 @@
|
|||||||
import { IBaseProtocolCore, IBaseProtocolSDK } from "./protocols.js";
|
import { IBaseProtocolCore } from "./protocols.js";
|
||||||
import type { ISender } from "./sender.js";
|
import type { ISender } from "./sender.js";
|
||||||
|
|
||||||
export type ILightPush = ISender &
|
export type ILightPush = ISender & { protocol: IBaseProtocolCore };
|
||||||
IBaseProtocolSDK & { protocol: IBaseProtocolCore };
|
|
||||||
|
@ -1,10 +1,23 @@
|
|||||||
import type { IEncoder, IMessage } from "./message.js";
|
import type { IEncoder, IMessage } from "./message.js";
|
||||||
import { ProtocolUseOptions, SDKProtocolResult } from "./protocols.js";
|
import { SDKProtocolResult } from "./protocols.js";
|
||||||
|
|
||||||
|
export type ISenderOptions = {
|
||||||
|
/**
|
||||||
|
* Enables retry of a message that was failed to be sent.
|
||||||
|
* @default false
|
||||||
|
*/
|
||||||
|
autoRetry?: boolean;
|
||||||
|
/**
|
||||||
|
* Sets number of attempts if `autoRetry` is enabled.
|
||||||
|
* @default 3
|
||||||
|
*/
|
||||||
|
maxAttempts?: number;
|
||||||
|
};
|
||||||
|
|
||||||
export interface ISender {
|
export interface ISender {
|
||||||
send: (
|
send: (
|
||||||
encoder: IEncoder,
|
encoder: IEncoder,
|
||||||
message: IMessage,
|
message: IMessage,
|
||||||
sendOptions?: ProtocolUseOptions
|
sendOptions?: ISenderOptions
|
||||||
) => Promise<SDKProtocolResult>;
|
) => Promise<SDKProtocolResult>;
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ interface Options {
|
|||||||
maintainPeersInterval?: number;
|
maintainPeersInterval?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
const DEFAULT_NUM_PEERS_TO_USE = 2;
|
export const DEFAULT_NUM_PEERS_TO_USE = 2;
|
||||||
const DEFAULT_MAINTAIN_PEERS_INTERVAL = 30_000;
|
const DEFAULT_MAINTAIN_PEERS_INTERVAL = 30_000;
|
||||||
|
|
||||||
export class BaseProtocolSDK implements IBaseProtocolSDK {
|
export class BaseProtocolSDK implements IBaseProtocolSDK {
|
||||||
@ -29,12 +29,12 @@ export class BaseProtocolSDK implements IBaseProtocolSDK {
|
|||||||
) {
|
) {
|
||||||
this.log = new Logger(`sdk:${core.multicodec}`);
|
this.log = new Logger(`sdk:${core.multicodec}`);
|
||||||
|
|
||||||
this.peerManager = new PeerManager(connectionManager, core, this.log);
|
|
||||||
|
|
||||||
this.numPeersToUse = options?.numPeersToUse ?? DEFAULT_NUM_PEERS_TO_USE;
|
this.numPeersToUse = options?.numPeersToUse ?? DEFAULT_NUM_PEERS_TO_USE;
|
||||||
const maintainPeersInterval =
|
const maintainPeersInterval =
|
||||||
options?.maintainPeersInterval ?? DEFAULT_MAINTAIN_PEERS_INTERVAL;
|
options?.maintainPeersInterval ?? DEFAULT_MAINTAIN_PEERS_INTERVAL;
|
||||||
|
|
||||||
|
this.peerManager = new PeerManager(connectionManager, core, this.log);
|
||||||
|
|
||||||
this.log.info(
|
this.log.info(
|
||||||
`Initializing BaseProtocolSDK with numPeersToUse: ${this.numPeersToUse}, maintainPeersInterval: ${maintainPeersInterval}ms`
|
`Initializing BaseProtocolSDK with numPeersToUse: ${this.numPeersToUse}, maintainPeersInterval: ${maintainPeersInterval}ms`
|
||||||
);
|
);
|
||||||
@ -42,7 +42,7 @@ export class BaseProtocolSDK implements IBaseProtocolSDK {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public get connectedPeers(): Peer[] {
|
public get connectedPeers(): Peer[] {
|
||||||
return this.peerManager.getPeers();
|
return this.peerManager.getPeers().slice(0, this.numPeersToUse);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
170
packages/sdk/src/protocols/light_push/light_push.spec.ts
Normal file
170
packages/sdk/src/protocols/light_push/light_push.spec.ts
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
import { Peer } from "@libp2p/interface";
|
||||||
|
import {
|
||||||
|
ConnectionManager,
|
||||||
|
createEncoder,
|
||||||
|
Encoder,
|
||||||
|
LightPushCodec
|
||||||
|
} from "@waku/core";
|
||||||
|
import { Libp2p, ProtocolError } from "@waku/interfaces";
|
||||||
|
import { utf8ToBytes } from "@waku/utils/bytes";
|
||||||
|
import { expect } from "chai";
|
||||||
|
import sinon from "sinon";
|
||||||
|
|
||||||
|
import { LightPush } from "./light_push.js";
|
||||||
|
|
||||||
|
const PUBSUB_TOPIC = "/waku/2/rs/1/4";
|
||||||
|
const CONTENT_TOPIC = "/test/1/waku-light-push/utf8";
|
||||||
|
|
||||||
|
describe("LightPush SDK", () => {
|
||||||
|
let libp2p: Libp2p;
|
||||||
|
let encoder: Encoder;
|
||||||
|
let lightPush: LightPush;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
libp2p = mockLibp2p();
|
||||||
|
encoder = createEncoder({ contentTopic: CONTENT_TOPIC });
|
||||||
|
lightPush = mockLightPush({ libp2p });
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should fail to send if pubsub topics are misconfigured", async () => {
|
||||||
|
lightPush = mockLightPush({ libp2p, pubsubTopics: ["/wrong"] });
|
||||||
|
|
||||||
|
const result = await lightPush.send(encoder, {
|
||||||
|
payload: utf8ToBytes("test")
|
||||||
|
});
|
||||||
|
const failures = result.failures ?? [];
|
||||||
|
|
||||||
|
expect(failures.length).to.be.eq(1);
|
||||||
|
expect(failures.some((v) => v.error === ProtocolError.TOPIC_NOT_CONFIGURED))
|
||||||
|
.to.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should fail to send if no connected peers found", async () => {
|
||||||
|
const result = await lightPush.send(encoder, {
|
||||||
|
payload: utf8ToBytes("test")
|
||||||
|
});
|
||||||
|
const failures = result.failures ?? [];
|
||||||
|
|
||||||
|
expect(failures.length).to.be.eq(1);
|
||||||
|
expect(failures.some((v) => v.error === ProtocolError.NO_PEER_AVAILABLE)).to
|
||||||
|
.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should send to specified number of peers of used peers", async () => {
|
||||||
|
libp2p = mockLibp2p({
|
||||||
|
peers: [mockPeer("1"), mockPeer("2"), mockPeer("3"), mockPeer("4")]
|
||||||
|
});
|
||||||
|
|
||||||
|
// check default value that should be 2
|
||||||
|
lightPush = mockLightPush({ libp2p });
|
||||||
|
let sendSpy = sinon.spy(
|
||||||
|
(_encoder: any, _message: any, peer: Peer) =>
|
||||||
|
({ success: peer.id }) as any
|
||||||
|
);
|
||||||
|
lightPush.protocol.send = sendSpy;
|
||||||
|
|
||||||
|
let result = await lightPush.send(encoder, {
|
||||||
|
payload: utf8ToBytes("test")
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(sendSpy.calledTwice).to.be.true;
|
||||||
|
expect(result.successes?.length).to.be.eq(2);
|
||||||
|
|
||||||
|
// check if setting another value works
|
||||||
|
lightPush = mockLightPush({ libp2p, numPeersToUse: 3 });
|
||||||
|
sendSpy = sinon.spy(
|
||||||
|
(_encoder: any, _message: any, peer: Peer) =>
|
||||||
|
({ success: peer.id }) as any
|
||||||
|
);
|
||||||
|
lightPush.protocol.send = sendSpy;
|
||||||
|
|
||||||
|
result = await lightPush.send(encoder, { payload: utf8ToBytes("test") });
|
||||||
|
|
||||||
|
expect(sendSpy.calledThrice).to.be.true;
|
||||||
|
expect(result.successes?.length).to.be.eq(3);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should retry on failure if specified", async () => {
|
||||||
|
libp2p = mockLibp2p({
|
||||||
|
peers: [mockPeer("1"), mockPeer("2")]
|
||||||
|
});
|
||||||
|
|
||||||
|
lightPush = mockLightPush({ libp2p });
|
||||||
|
let sendSpy = sinon.spy((_encoder: any, _message: any, peer: Peer) => {
|
||||||
|
if (peer.id.toString() === "1") {
|
||||||
|
return { success: peer.id };
|
||||||
|
}
|
||||||
|
|
||||||
|
return { failure: { error: "problem" } };
|
||||||
|
});
|
||||||
|
lightPush.protocol.send = sendSpy as any;
|
||||||
|
const attemptRetriesSpy = sinon.spy(lightPush["attemptRetries"]);
|
||||||
|
lightPush["attemptRetries"] = attemptRetriesSpy;
|
||||||
|
|
||||||
|
const result = await lightPush.send(
|
||||||
|
encoder,
|
||||||
|
{ payload: utf8ToBytes("test") },
|
||||||
|
{ autoRetry: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(attemptRetriesSpy.calledOnce).to.be.true;
|
||||||
|
expect(result.successes?.length).to.be.eq(1);
|
||||||
|
expect(result.failures?.length).to.be.eq(1);
|
||||||
|
|
||||||
|
sendSpy = sinon.spy(() => ({ failure: { error: "problem" } })) as any;
|
||||||
|
await lightPush["attemptRetries"](sendSpy as any);
|
||||||
|
|
||||||
|
expect(sendSpy.callCount).to.be.eq(3);
|
||||||
|
|
||||||
|
sendSpy = sinon.spy(() => ({ failure: { error: "problem" } })) as any;
|
||||||
|
await lightPush["attemptRetries"](sendSpy as any, 2);
|
||||||
|
|
||||||
|
expect(sendSpy.callCount).to.be.eq(2);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
type MockLibp2pOptions = {
|
||||||
|
peers?: Peer[];
|
||||||
|
};
|
||||||
|
|
||||||
|
function mockLibp2p(options?: MockLibp2pOptions): Libp2p {
|
||||||
|
const peers = options?.peers || [];
|
||||||
|
const peerStore = {
|
||||||
|
get: (id: any) => Promise.resolve(peers.find((p) => p.id === id))
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
peerStore,
|
||||||
|
getPeers: () => peers.map((p) => p.id),
|
||||||
|
components: {
|
||||||
|
events: new EventTarget(),
|
||||||
|
connectionManager: {
|
||||||
|
getConnections: () => []
|
||||||
|
} as any,
|
||||||
|
peerStore
|
||||||
|
}
|
||||||
|
} as unknown as Libp2p;
|
||||||
|
}
|
||||||
|
|
||||||
|
type MockLightPushOptions = {
|
||||||
|
libp2p: Libp2p;
|
||||||
|
pubsubTopics?: string[];
|
||||||
|
numPeersToUse?: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
function mockLightPush(options: MockLightPushOptions): LightPush {
|
||||||
|
return new LightPush(
|
||||||
|
{
|
||||||
|
configuredPubsubTopics: options.pubsubTopics || [PUBSUB_TOPIC]
|
||||||
|
} as ConnectionManager,
|
||||||
|
options.libp2p,
|
||||||
|
{ numPeersToUse: options.numPeersToUse }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function mockPeer(id: string): Peer {
|
||||||
|
return {
|
||||||
|
id,
|
||||||
|
protocols: [LightPushCodec]
|
||||||
|
} as unknown as Peer;
|
||||||
|
}
|
@ -6,53 +6,51 @@ import {
|
|||||||
LightPushCore
|
LightPushCore
|
||||||
} from "@waku/core";
|
} from "@waku/core";
|
||||||
import {
|
import {
|
||||||
|
type CoreProtocolResult,
|
||||||
Failure,
|
Failure,
|
||||||
type IEncoder,
|
type IEncoder,
|
||||||
ILightPush,
|
ILightPush,
|
||||||
type IMessage,
|
type IMessage,
|
||||||
|
type ISenderOptions,
|
||||||
type Libp2p,
|
type Libp2p,
|
||||||
type ProtocolCreateOptions,
|
type ProtocolCreateOptions,
|
||||||
ProtocolError,
|
ProtocolError,
|
||||||
ProtocolUseOptions,
|
|
||||||
SDKProtocolResult
|
SDKProtocolResult
|
||||||
} from "@waku/interfaces";
|
} from "@waku/interfaces";
|
||||||
import { ensurePubsubTopicIsConfigured, Logger } from "@waku/utils";
|
import { ensurePubsubTopicIsConfigured, Logger } from "@waku/utils";
|
||||||
|
|
||||||
import { ReliabilityMonitorManager } from "../../reliability_monitor/index.js";
|
import { DEFAULT_NUM_PEERS_TO_USE } from "../base_protocol.js";
|
||||||
import { SenderReliabilityMonitor } from "../../reliability_monitor/sender.js";
|
|
||||||
import { BaseProtocolSDK } from "../base_protocol.js";
|
|
||||||
|
|
||||||
const log = new Logger("sdk:light-push");
|
const log = new Logger("sdk:light-push");
|
||||||
|
|
||||||
class LightPush extends BaseProtocolSDK implements ILightPush {
|
const DEFAULT_MAX_ATTEMPTS = 3;
|
||||||
public readonly protocol: LightPushCore;
|
const DEFAULT_SEND_OPTIONS: ISenderOptions = {
|
||||||
|
autoRetry: false,
|
||||||
|
maxAttempts: DEFAULT_MAX_ATTEMPTS
|
||||||
|
};
|
||||||
|
|
||||||
private readonly reliabilityMonitor: SenderReliabilityMonitor;
|
type RetryCallback = (peer: Peer) => Promise<CoreProtocolResult>;
|
||||||
|
|
||||||
|
export class LightPush implements ILightPush {
|
||||||
|
private numPeersToUse: number = DEFAULT_NUM_PEERS_TO_USE;
|
||||||
|
public readonly protocol: LightPushCore;
|
||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
connectionManager: ConnectionManager,
|
connectionManager: ConnectionManager,
|
||||||
private libp2p: Libp2p,
|
private libp2p: Libp2p,
|
||||||
options?: ProtocolCreateOptions
|
options?: ProtocolCreateOptions
|
||||||
) {
|
) {
|
||||||
super(
|
this.numPeersToUse = options?.numPeersToUse ?? DEFAULT_NUM_PEERS_TO_USE;
|
||||||
new LightPushCore(connectionManager.configuredPubsubTopics, libp2p),
|
this.protocol = new LightPushCore(
|
||||||
connectionManager,
|
connectionManager.configuredPubsubTopics,
|
||||||
{
|
libp2p
|
||||||
numPeersToUse: options?.numPeersToUse
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
this.reliabilityMonitor = ReliabilityMonitorManager.createSenderMonitor(
|
|
||||||
this.renewPeer.bind(this)
|
|
||||||
);
|
|
||||||
|
|
||||||
this.protocol = this.core as LightPushCore;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async send(
|
public async send(
|
||||||
encoder: IEncoder,
|
encoder: IEncoder,
|
||||||
message: IMessage,
|
message: IMessage,
|
||||||
_options?: ProtocolUseOptions
|
options: ISenderOptions = DEFAULT_SEND_OPTIONS
|
||||||
): Promise<SDKProtocolResult> {
|
): Promise<SDKProtocolResult> {
|
||||||
const successes: PeerId[] = [];
|
const successes: PeerId[] = [];
|
||||||
const failures: Failure[] = [];
|
const failures: Failure[] = [];
|
||||||
@ -105,14 +103,10 @@ class LightPush extends BaseProtocolSDK implements ILightPush {
|
|||||||
if (failure) {
|
if (failure) {
|
||||||
failures.push(failure);
|
failures.push(failure);
|
||||||
|
|
||||||
const connectedPeer = this.connectedPeers.find((connectedPeer) =>
|
if (options?.autoRetry) {
|
||||||
connectedPeer.id.equals(failure.peerId)
|
void this.attemptRetries(
|
||||||
);
|
(peer: Peer) => this.protocol.send(encoder, message, peer),
|
||||||
|
options.maxAttempts
|
||||||
if (connectedPeer) {
|
|
||||||
void this.reliabilityMonitor.attemptRetriesOrRenew(
|
|
||||||
connectedPeer.id,
|
|
||||||
() => this.protocol.send(encoder, message, connectedPeer)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -129,6 +123,32 @@ class LightPush extends BaseProtocolSDK implements ILightPush {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async attemptRetries(
|
||||||
|
fn: RetryCallback,
|
||||||
|
maxAttempts?: number
|
||||||
|
): Promise<void> {
|
||||||
|
maxAttempts = maxAttempts || DEFAULT_MAX_ATTEMPTS;
|
||||||
|
const connectedPeers = await this.getConnectedPeers();
|
||||||
|
|
||||||
|
if (connectedPeers.length === 0) {
|
||||||
|
log.warn("Cannot retry with no connected peers.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < maxAttempts; i++) {
|
||||||
|
const peer = connectedPeers[i % connectedPeers.length]; // always present as we checked for the length already
|
||||||
|
const response = await fn(peer);
|
||||||
|
|
||||||
|
if (response.success) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info(
|
||||||
|
`Attempted retry for peer:${peer.id} failed with:${response?.failure?.error}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async getConnectedPeers(): Promise<Peer[]> {
|
private async getConnectedPeers(): Promise<Peer[]> {
|
||||||
const peerIDs = this.libp2p.getPeers();
|
const peerIDs = this.libp2p.getPeers();
|
||||||
|
|
||||||
|
@ -7,14 +7,12 @@ import {
|
|||||||
} from "@waku/interfaces";
|
} from "@waku/interfaces";
|
||||||
|
|
||||||
import { ReceiverReliabilityMonitor } from "./receiver.js";
|
import { ReceiverReliabilityMonitor } from "./receiver.js";
|
||||||
import { SenderReliabilityMonitor } from "./sender.js";
|
|
||||||
|
|
||||||
export class ReliabilityMonitorManager {
|
export class ReliabilityMonitorManager {
|
||||||
private static receiverMonitors: Map<
|
private static receiverMonitors: Map<
|
||||||
PubsubTopic,
|
PubsubTopic,
|
||||||
ReceiverReliabilityMonitor
|
ReceiverReliabilityMonitor
|
||||||
> = new Map();
|
> = new Map();
|
||||||
private static senderMonitor: SenderReliabilityMonitor | undefined;
|
|
||||||
|
|
||||||
public static createReceiverMonitor(
|
public static createReceiverMonitor(
|
||||||
pubsubTopic: PubsubTopic,
|
pubsubTopic: PubsubTopic,
|
||||||
@ -44,22 +42,10 @@ export class ReliabilityMonitorManager {
|
|||||||
return monitor;
|
return monitor;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static createSenderMonitor(
|
|
||||||
renewPeer: (peerId: PeerId) => Promise<Peer | undefined>
|
|
||||||
): SenderReliabilityMonitor {
|
|
||||||
if (!ReliabilityMonitorManager.senderMonitor) {
|
|
||||||
ReliabilityMonitorManager.senderMonitor = new SenderReliabilityMonitor(
|
|
||||||
renewPeer
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return ReliabilityMonitorManager.senderMonitor;
|
|
||||||
}
|
|
||||||
|
|
||||||
private constructor() {}
|
private constructor() {}
|
||||||
|
|
||||||
public static stop(pubsubTopic: PubsubTopic): void {
|
public static stop(pubsubTopic: PubsubTopic): void {
|
||||||
this.receiverMonitors.delete(pubsubTopic);
|
this.receiverMonitors.delete(pubsubTopic);
|
||||||
this.senderMonitor = undefined;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static stopAll(): void {
|
public static stopAll(): void {
|
||||||
@ -67,7 +53,6 @@ export class ReliabilityMonitorManager {
|
|||||||
monitor.setMaxMissedMessagesThreshold(undefined);
|
monitor.setMaxMissedMessagesThreshold(undefined);
|
||||||
monitor.setMaxPingFailures(undefined);
|
monitor.setMaxPingFailures(undefined);
|
||||||
this.receiverMonitors.delete(pubsubTopic);
|
this.receiverMonitors.delete(pubsubTopic);
|
||||||
this.senderMonitor = undefined;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,65 +0,0 @@
|
|||||||
import type { Peer, PeerId } from "@libp2p/interface";
|
|
||||||
import { CoreProtocolResult, PeerIdStr } from "@waku/interfaces";
|
|
||||||
import { Logger } from "@waku/utils";
|
|
||||||
|
|
||||||
const log = new Logger("sdk:sender:reliability_monitor");
|
|
||||||
|
|
||||||
const DEFAULT_MAX_ATTEMPTS_BEFORE_RENEWAL = 3;
|
|
||||||
|
|
||||||
export class SenderReliabilityMonitor {
|
|
||||||
private attempts: Map<PeerIdStr, number> = new Map();
|
|
||||||
private readonly maxAttemptsBeforeRenewal =
|
|
||||||
DEFAULT_MAX_ATTEMPTS_BEFORE_RENEWAL;
|
|
||||||
|
|
||||||
public constructor(
|
|
||||||
private renewPeer: (peerId: PeerId) => Promise<Peer | undefined>
|
|
||||||
) {}
|
|
||||||
|
|
||||||
public async attemptRetriesOrRenew(
|
|
||||||
peerId: PeerId,
|
|
||||||
protocolSend: () => Promise<CoreProtocolResult>
|
|
||||||
): Promise<void> {
|
|
||||||
const peerIdStr = peerId.toString();
|
|
||||||
const currentAttempts = this.attempts.get(peerIdStr) || 0;
|
|
||||||
this.attempts.set(peerIdStr, currentAttempts + 1);
|
|
||||||
|
|
||||||
if (currentAttempts + 1 < this.maxAttemptsBeforeRenewal) {
|
|
||||||
try {
|
|
||||||
const result = await protocolSend();
|
|
||||||
if (result.success) {
|
|
||||||
log.info(`Successfully sent message after retry to ${peerIdStr}`);
|
|
||||||
this.attempts.delete(peerIdStr);
|
|
||||||
} else {
|
|
||||||
log.error(
|
|
||||||
`Failed to send message after retry to ${peerIdStr}: ${result.failure}`
|
|
||||||
);
|
|
||||||
await this.attemptRetriesOrRenew(peerId, protocolSend);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
log.error(
|
|
||||||
`Failed to send message after retry to ${peerIdStr}: ${error}`
|
|
||||||
);
|
|
||||||
await this.attemptRetriesOrRenew(peerId, protocolSend);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
const newPeer = await this.renewPeer(peerId);
|
|
||||||
if (newPeer) {
|
|
||||||
log.info(
|
|
||||||
`Renewed peer ${peerId.toString()} to ${newPeer.id.toString()}`
|
|
||||||
);
|
|
||||||
|
|
||||||
this.attempts.delete(peerIdStr);
|
|
||||||
this.attempts.set(newPeer.id.toString(), 0);
|
|
||||||
await protocolSend();
|
|
||||||
} else {
|
|
||||||
log.error(
|
|
||||||
`Failed to renew peer ${peerId.toString()}: New peer is undefined`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
log.error(`Failed to renew peer ${peerId.toString()}: ${error}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -72,7 +72,7 @@ export class WakuNode implements IWaku {
|
|||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
public readonly pubsubTopics: PubsubTopic[],
|
public readonly pubsubTopics: PubsubTopic[],
|
||||||
options: WakuOptions,
|
options: CreateWakuNodeOptions,
|
||||||
libp2p: Libp2p,
|
libp2p: Libp2p,
|
||||||
protocolsEnabled: ProtocolsEnabled,
|
protocolsEnabled: ProtocolsEnabled,
|
||||||
relay?: IRelay
|
relay?: IRelay
|
||||||
@ -111,12 +111,12 @@ export class WakuNode implements IWaku {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (protocolsEnabled.lightpush) {
|
if (protocolsEnabled.lightpush) {
|
||||||
const lightPush = wakuLightPush(this.connectionManager);
|
const lightPush = wakuLightPush(this.connectionManager, options);
|
||||||
this.lightPush = lightPush(libp2p);
|
this.lightPush = lightPush(libp2p);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (protocolsEnabled.filter) {
|
if (protocolsEnabled.filter) {
|
||||||
const filter = wakuFilter(this.connectionManager);
|
const filter = wakuFilter(this.connectionManager, options);
|
||||||
this.filter = filter(libp2p);
|
this.filter = filter(libp2p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,7 +17,8 @@ import {
|
|||||||
TestShardInfo
|
TestShardInfo
|
||||||
} from "./utils.js";
|
} from "./utils.js";
|
||||||
|
|
||||||
describe("Node Health Status Matrix Tests", function () {
|
// TODO(weboko): resolve https://github.com/waku-org/js-waku/issues/2186
|
||||||
|
describe.skip("Node Health Status Matrix Tests", function () {
|
||||||
let waku: LightNode;
|
let waku: LightNode;
|
||||||
let serviceNodes: ServiceNode[];
|
let serviceNodes: ServiceNode[];
|
||||||
|
|
||||||
@ -44,9 +45,7 @@ describe("Node Health Status Matrix Tests", function () {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (lightPushPeers > 0) {
|
if (lightPushPeers > 0) {
|
||||||
await waku.lightPush.send(TestEncoder, messagePayload, {
|
await waku.lightPush.send(TestEncoder, messagePayload);
|
||||||
forceUseAllPeers: true
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filterPeers > 0) {
|
if (filterPeers > 0) {
|
||||||
|
@ -17,7 +17,8 @@ import {
|
|||||||
|
|
||||||
const NUM_NODES = [0, 1, 2, 3];
|
const NUM_NODES = [0, 1, 2, 3];
|
||||||
|
|
||||||
describe("Health Manager", function () {
|
// TODO(weboko): resolve https://github.com/waku-org/js-waku/issues/2186
|
||||||
|
describe.skip("Health Manager", function () {
|
||||||
this.timeout(10_000);
|
this.timeout(10_000);
|
||||||
|
|
||||||
let waku: LightNode;
|
let waku: LightNode;
|
||||||
|
@ -1,88 +0,0 @@
|
|||||||
import { LightNode } from "@waku/interfaces";
|
|
||||||
import { createEncoder, utf8ToBytes } from "@waku/sdk";
|
|
||||||
import { expect } from "chai";
|
|
||||||
import { describe } from "mocha";
|
|
||||||
|
|
||||||
import {
|
|
||||||
afterEachCustom,
|
|
||||||
beforeEachCustom,
|
|
||||||
DefaultTestShardInfo,
|
|
||||||
DefaultTestSingleShardInfo,
|
|
||||||
runMultipleNodes,
|
|
||||||
ServiceNodesFleet,
|
|
||||||
teardownNodesWithRedundancy
|
|
||||||
} from "../../src/index.js";
|
|
||||||
import { TestContentTopic } from "../filter/utils.js";
|
|
||||||
|
|
||||||
describe("Waku Light Push: Connection Management: E2E", function () {
|
|
||||||
this.timeout(15000);
|
|
||||||
let waku: LightNode;
|
|
||||||
let serviceNodes: ServiceNodesFleet;
|
|
||||||
|
|
||||||
beforeEachCustom(this, async () => {
|
|
||||||
[serviceNodes, waku] = await runMultipleNodes(
|
|
||||||
this.ctx,
|
|
||||||
DefaultTestShardInfo,
|
|
||||||
{ lightpush: true, filter: true },
|
|
||||||
undefined,
|
|
||||||
5
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEachCustom(this, async () => {
|
|
||||||
await teardownNodesWithRedundancy(serviceNodes, waku);
|
|
||||||
});
|
|
||||||
|
|
||||||
const encoder = createEncoder({
|
|
||||||
pubsubTopicShardInfo: DefaultTestSingleShardInfo,
|
|
||||||
contentTopic: TestContentTopic
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should push to needed amount of connections", async function () {
|
|
||||||
const { successes, failures } = await waku.lightPush.send(encoder, {
|
|
||||||
payload: utf8ToBytes("Hello_World")
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(successes.length).to.be.equal(waku.lightPush.numPeersToUse);
|
|
||||||
expect(failures?.length || 0).to.equal(0);
|
|
||||||
});
|
|
||||||
|
|
||||||
// skipped because of https://github.com/waku-org/js-waku/pull/2155#discussion_r1787452696
|
|
||||||
it.skip("Failed peers are renewed", async function () {
|
|
||||||
// send a lightpush request -- should have all successes
|
|
||||||
const response1 = await waku.lightPush.send(
|
|
||||||
encoder,
|
|
||||||
{
|
|
||||||
payload: utf8ToBytes("Hello_World")
|
|
||||||
},
|
|
||||||
{ forceUseAllPeers: true }
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(response1.successes.length).to.be.equal(
|
|
||||||
waku.lightPush.numPeersToUse
|
|
||||||
);
|
|
||||||
|
|
||||||
const { successes, failures } = await waku.lightPush.send(encoder, {
|
|
||||||
payload: utf8ToBytes("Hello_World")
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(successes.length).to.be.equal(1);
|
|
||||||
expect(failures?.length || 0).to.equal(0);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should fail to send if no connections available", async function () {
|
|
||||||
const connections = waku.libp2p.getConnections();
|
|
||||||
await Promise.all(
|
|
||||||
connections.map((c) =>
|
|
||||||
waku.connectionManager.dropConnection(c.remotePeer)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
const { successes, failures } = await waku.lightPush.send(encoder, {
|
|
||||||
payload: utf8ToBytes("Hello_World")
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(successes.length).to.be.equal(0);
|
|
||||||
expect(failures?.length).to.equal(1);
|
|
||||||
});
|
|
||||||
});
|
|
@ -432,13 +432,9 @@ describe("Waku Light Push (named sharding): Multiple PubsubTopics", function ()
|
|||||||
const { failures: f1 } = await waku.lightPush.send(customEncoder1, {
|
const { failures: f1 } = await waku.lightPush.send(customEncoder1, {
|
||||||
payload: utf8ToBytes("M1")
|
payload: utf8ToBytes("M1")
|
||||||
});
|
});
|
||||||
const { failures: f2 } = await waku.lightPush.send(
|
const { failures: f2 } = await waku.lightPush.send(customEncoder2, {
|
||||||
customEncoder2,
|
payload: utf8ToBytes("M2")
|
||||||
{
|
});
|
||||||
payload: utf8ToBytes("M2")
|
|
||||||
},
|
|
||||||
{ forceUseAllPeers: true }
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(f1).to.be.empty;
|
expect(f1).to.be.empty;
|
||||||
expect(f2).to.be.empty;
|
expect(f2).to.be.empty;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user