Skip to content

Commit a341371

Browse files
committed
Merge commit '0773a8a' into jribbink/sdk-subscriptions
2 parents f2c9f79 + 0773a8a commit a341371

File tree

2 files changed

+47
-28
lines changed

2 files changed

+47
-28
lines changed

packages/transport-http/src/subscribe/subscription-manager.test.ts

+8-13
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@ import {
77
SubscriptionDataMessage,
88
UnsubscribeMessageRequest,
99
} from "./models"
10-
import {SubscriptionManager} from "./subscription-manager"
10+
import {
11+
SubscriptionManager,
12+
SubscriptionManagerConfig,
13+
} from "./subscription-manager"
1114
import {SdkTransport} from "@onflow/typedefs"
1215

1316
jest.mock("./websocket", () => ({
@@ -25,10 +28,8 @@ describe("WsSubscriptionTransport", () => {
2528
})
2629

2730
test("does not connect to the socket when no subscriptions are made", async () => {
28-
const config = {
31+
const config: SubscriptionManagerConfig = {
2932
node: "wss://localhost:8080",
30-
reconnectInterval: 1000,
31-
reconnectAttempts: 10,
3233
}
3334

3435
new SubscriptionManager(config)
@@ -38,10 +39,8 @@ describe("WsSubscriptionTransport", () => {
3839
})
3940

4041
test("disconnects from the socket when the last subscription is removed", async () => {
41-
const config = {
42+
const config: SubscriptionManagerConfig = {
4243
node: "wss://localhost:8080",
43-
reconnectInterval: 1000,
44-
reconnectAttempts: 10,
4544
}
4645
const streamController = new SubscriptionManager(config)
4746
const topic = "topic" as SdkTransport.SubscriptionTopic
@@ -90,10 +89,8 @@ describe("WsSubscriptionTransport", () => {
9089
})
9190

9291
test("subscribes, receives data, and unsubscribes", async () => {
93-
const config = {
92+
const config: SubscriptionManagerConfig = {
9493
node: "wss://localhost:8080",
95-
reconnectInterval: 1000,
96-
reconnectAttempts: 10,
9794
}
9895
const streamController = new SubscriptionManager(config)
9996
const topic = "topic" as SdkTransport.SubscriptionTopic
@@ -162,10 +159,8 @@ describe("WsSubscriptionTransport", () => {
162159
})
163160

164161
test("reconnects to stream on close", async () => {
165-
const config = {
162+
const config: SubscriptionManagerConfig = {
166163
node: "wss://localhost:8080",
167-
reconnectInterval: 1000,
168-
reconnectAttempts: 1,
169164
}
170165
const streamController = new SubscriptionManager(config)
171166
const topic = "topic" as SdkTransport.SubscriptionTopic

packages/transport-http/src/subscribe/subscription-manager.ts

+39-15
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ import * as logger from "@onflow/util-logger"
1515

1616
const WS_OPEN = 1
1717

18+
type DeepRequired<T> = Required<{
19+
[K in keyof T]: DeepRequired<T[K]>
20+
}>
21+
1822
interface SubscriptionInfo<T extends SdkTransport.SubscriptionTopic> {
1923
// Internal ID for the subscription
2024
id: number
@@ -30,35 +34,49 @@ interface SubscriptionInfo<T extends SdkTransport.SubscriptionTopic> {
3034
onError: (error: Error) => void
3135
}
3236

33-
interface WsTransportConfig {
37+
export interface SubscriptionManagerConfig {
3438
/**
3539
* The URL of the node to connect to
3640
*/
3741
node: string
3842
/**
39-
* Starting interval for reconnection attempts in milliseconds, exponential backoff is applied
40-
* @default 500
41-
*/
42-
reconnectInterval?: number
43-
/**
44-
* The number of reconnection attempts before giving up
45-
* @default 5
43+
* Options for reconnecting to the server
4644
*/
47-
reconnectAttempts?: number
45+
reconnectOptions?: {
46+
/**
47+
* The initial delay in milliseconds before reconnecting
48+
* @default 500
49+
*/
50+
initialReconnectDelay?: number
51+
/**
52+
* The maximum number of reconnection attempts
53+
* @default 5
54+
*/
55+
reconnectAttempts?: number
56+
/**
57+
* The maximum delay in milliseconds between reconnection attempts
58+
* @default 5000
59+
*/
60+
maxReconnectDelay?: number
61+
}
4862
}
4963

5064
export class SubscriptionManager {
5165
private counter = 0
5266
private subscriptions: SubscriptionInfo<SdkTransport.SubscriptionTopic>[] = []
5367
private socket: WebSocket | null = null
54-
private config: Required<WsTransportConfig>
68+
private config: DeepRequired<SubscriptionManagerConfig>
5569
private reconnectAttempts = 0
5670

57-
constructor(config: WsTransportConfig) {
71+
constructor(config: SubscriptionManagerConfig) {
5872
this.config = {
59-
reconnectInterval: 500,
60-
reconnectAttempts: 5,
6173
...config,
74+
reconnectOptions: {
75+
initialReconnectDelay: 500,
76+
reconnectAttempts: 5,
77+
maxReconnectDelay: 5000,
78+
...config.reconnectOptions,
79+
},
6280
}
6381
}
6482

@@ -129,7 +147,9 @@ export class SubscriptionManager {
129147
})
130148

131149
// Validate the number of reconnection attempts
132-
if (this.reconnectAttempts >= this.config.reconnectAttempts) {
150+
if (
151+
this.reconnectAttempts >= this.config.reconnectOptions.reconnectAttempts
152+
) {
133153
logger.log({
134154
level: logger.LEVELS.error,
135155
title: "WebSocket Error",
@@ -288,6 +308,10 @@ export class SubscriptionManager {
288308
* @returns The backoff interval in milliseconds
289309
*/
290310
private get backoffInterval() {
291-
return this.config.reconnectInterval * (this.reconnectAttempts ^ 2)
311+
return Math.min(
312+
this.config.reconnectOptions.maxReconnectDelay,
313+
this.config.reconnectOptions.initialReconnectDelay *
314+
2 ** this.reconnectAttempts
315+
)
292316
}
293317
}

0 commit comments

Comments
 (0)