Skip to content

Commit 71ba3a1

Browse files
authored
Remove minimum presence timeout (#446)
feat(presence): remove minimum presence timeout Remove minimum limit for presence timeout (was 20 seconds) to make it possible specify shorter intervals. fix(shared-worker): fix issue because of which similar requests didn't stacked Fix issue because of which channels not aggregated and caused separate heartbeat requests.
1 parent 36e0ec3 commit 71ba3a1

File tree

13 files changed

+131
-65
lines changed

13 files changed

+131
-65
lines changed

.pubnub.yml

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
---
22
changelog:
3+
- date: 2025-03-20
4+
version: v9.3.0
5+
changes:
6+
- type: feature
7+
text: "Remove minimum limit for presence timeout (was 20 seconds) to make it possible specify shorter intervals."
8+
- type: bug
9+
text: "Fix issue because of which channels not aggregated and caused separate heartbeat requests."
310
- date: 2025-03-19
411
version: v9.2.0
512
changes:
@@ -1185,7 +1192,7 @@ supported-platforms:
11851192
- 'Ubuntu 14.04 and up'
11861193
- 'Windows 7 and up'
11871194
version: 'Pubnub Javascript for Node'
1188-
version: '9.2.0'
1195+
version: '9.3.0'
11891196
sdks:
11901197
- full-name: PubNub Javascript SDK
11911198
short-name: Javascript
@@ -1201,7 +1208,7 @@ sdks:
12011208
- distribution-type: source
12021209
distribution-repository: GitHub release
12031210
package-name: pubnub.js
1204-
location: https://github.com/pubnub/javascript/archive/refs/tags/v9.2.0.zip
1211+
location: https://github.com/pubnub/javascript/archive/refs/tags/v9.3.0.zip
12051212
requires:
12061213
- name: 'agentkeepalive'
12071214
min-version: '3.5.2'
@@ -1872,7 +1879,7 @@ sdks:
18721879
- distribution-type: library
18731880
distribution-repository: GitHub release
18741881
package-name: pubnub.js
1875-
location: https://github.com/pubnub/javascript/releases/download/v9.2.0/pubnub.9.2.0.js
1882+
location: https://github.com/pubnub/javascript/releases/download/v9.3.0/pubnub.9.3.0.js
18761883
requires:
18771884
- name: 'agentkeepalive'
18781885
min-version: '3.5.2'

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
## v9.3.0
2+
March 20 2025
3+
4+
#### Added
5+
- Remove minimum limit for presence timeout (was 20 seconds) to make it possible specify shorter intervals.
6+
7+
#### Fixed
8+
- Fix issue because of which channels not aggregated and caused separate heartbeat requests.
9+
110
## v9.2.0
211
March 19 2025
312

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ Watch [Getting Started with PubNub JS SDK](https://app.dashcam.io/replay/64ee0d2
2727
npm install pubnub
2828
```
2929
* or download one of our builds from our CDN:
30-
* https://cdn.pubnub.com/sdk/javascript/pubnub.9.2.0.js
31-
* https://cdn.pubnub.com/sdk/javascript/pubnub.9.2.0.min.js
30+
* https://cdn.pubnub.com/sdk/javascript/pubnub.9.3.0.js
31+
* https://cdn.pubnub.com/sdk/javascript/pubnub.9.3.0.min.js
3232
3333
2. Configure your keys:
3434

dist/web/pubnub.js

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3594,9 +3594,9 @@
35943594
*/
35953595
const PRESENCE_TIMEOUT = 300;
35963596
/**
3597-
* Minimum user presence timeout.
3597+
* Maximum user presence timeout.
35983598
*/
3599-
const PRESENCE_TIMEOUT_MINIMUM = 20;
3599+
const PRESENCE_TIMEOUT_MAXIMUM = 320;
36003600
/**
36013601
* Apply configuration default values.
36023602
*
@@ -3637,10 +3637,17 @@
36373637
publishKey: configurationCopy.publishKey,
36383638
secretKey: configurationCopy.secretKey,
36393639
};
3640-
if (configurationCopy.presenceTimeout !== undefined && configurationCopy.presenceTimeout < PRESENCE_TIMEOUT_MINIMUM) {
3641-
configurationCopy.presenceTimeout = PRESENCE_TIMEOUT_MINIMUM;
3642-
// eslint-disable-next-line no-console
3643-
console.log('WARNING: Presence timeout is less than the minimum. Using minimum value: ', PRESENCE_TIMEOUT_MINIMUM);
3640+
if (configurationCopy.presenceTimeout !== undefined) {
3641+
if (configurationCopy.presenceTimeout > PRESENCE_TIMEOUT_MAXIMUM) {
3642+
configurationCopy.presenceTimeout = PRESENCE_TIMEOUT_MAXIMUM;
3643+
// eslint-disable-next-line no-console
3644+
console.warn('WARNING: Presence timeout is larger than the maximum. Using maximum value: ', PRESENCE_TIMEOUT_MAXIMUM);
3645+
}
3646+
else if (configurationCopy.presenceTimeout <= 0) {
3647+
// eslint-disable-next-line no-console
3648+
console.warn('WARNING: Presence timeout should be larger than zero.');
3649+
delete configurationCopy.presenceTimeout;
3650+
}
36443651
}
36453652
if (configurationCopy.presenceTimeout !== undefined)
36463653
configurationCopy.heartbeatInterval = configurationCopy.presenceTimeout / 2 - 1;
@@ -3932,7 +3939,7 @@
39323939
return base.PubNubFile;
39333940
},
39343941
get version() {
3935-
return '9.2.0';
3942+
return '9.3.0';
39363943
},
39373944
getVersion() {
39383945
return this.version;

dist/web/pubnub.min.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/web/pubnub.worker.js

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -406,7 +406,7 @@
406406
const hbRequests = (hbRequestsBySubscriptionKey !== null && hbRequestsBySubscriptionKey !== void 0 ? hbRequestsBySubscriptionKey : {})[heartbeatRequestKey];
407407
notifyRequestProcessing('start', [client], new Date().toISOString(), request);
408408
if (!request) {
409-
consoleLog(`Previous heartbeat request has been sent less than ${client.heartbeatInterval} seconds ago. Skipping...`);
409+
consoleLog(`Previous heartbeat request has been sent less than ${client.heartbeatInterval} seconds ago. Skipping...`, client);
410410
let response;
411411
let body;
412412
// Pulling out previous response.
@@ -855,30 +855,36 @@
855855
const { channels, channelGroups, response } = hbRequestsBySubscriptionKey[heartbeatRequestKey];
856856
aggregatedState = (_d = client.heartbeat.presenceState) !== null && _d !== void 0 ? _d : {};
857857
aggregated =
858-
includesStrings(channels, client.heartbeat.channels) &&
859-
includesStrings(channelGroups, client.heartbeat.channelGroups);
858+
includesStrings(channels, channelsForAnnouncement) &&
859+
includesStrings(channelGroups, channelGroupsForAnnouncement);
860860
if (response)
861861
failedPreviousRequest = response[0].status >= 400;
862862
}
863+
// Find minimum heartbeat interval which maybe required to use.
864+
let minimumHeartbeatInterval = client.heartbeatInterval;
865+
for (const client of clients) {
866+
if (client.heartbeatInterval)
867+
minimumHeartbeatInterval = Math.min(minimumHeartbeatInterval, client.heartbeatInterval);
868+
}
863869
if (aggregated) {
864-
const expectedTimestamp = hbRequestsBySubscriptionKey[heartbeatRequestKey].timestamp + client.heartbeatInterval * 1000;
870+
const expectedTimestamp = hbRequestsBySubscriptionKey[heartbeatRequestKey].timestamp + minimumHeartbeatInterval * 1000;
865871
const currentTimestamp = Date.now();
866872
// Check whether it is too soon to send request or not (5 is leeway which let send request a bit earlier).
867873
// Request should be sent if previous attempt failed.
868874
if (!failedPreviousRequest && currentTimestamp < expectedTimestamp && expectedTimestamp - currentTimestamp > 5000)
869875
return undefined;
870-
delete hbRequestsBySubscriptionKey[heartbeatRequestKey].response;
871-
// Aggregate channels for similar clients which is pending for heartbeat.
872-
for (const client of clients) {
873-
const { heartbeat } = client;
874-
if (heartbeat === undefined || client.clientIdentifier === event.clientIdentifier)
875-
continue;
876-
// Append presence state from the client (will override previously set value if already set).
877-
if (heartbeat.presenceState)
878-
aggregatedState = Object.assign(Object.assign({}, aggregatedState), heartbeat.presenceState);
879-
channelGroupsForAnnouncement.push(...heartbeat.channelGroups.filter((channel) => !channelGroupsForAnnouncement.includes(channel)));
880-
channelsForAnnouncement.push(...heartbeat.channels.filter((channel) => !channelsForAnnouncement.includes(channel)));
881-
}
876+
}
877+
delete hbRequestsBySubscriptionKey[heartbeatRequestKey].response;
878+
// Aggregate channels for similar clients which is pending for heartbeat.
879+
for (const client of clients) {
880+
const { heartbeat } = client;
881+
if (heartbeat === undefined || client.clientIdentifier === event.clientIdentifier)
882+
continue;
883+
// Append presence state from the client (will override previously set value if already set).
884+
if (heartbeat.presenceState)
885+
aggregatedState = Object.assign(Object.assign({}, aggregatedState), heartbeat.presenceState);
886+
channelGroupsForAnnouncement.push(...heartbeat.channelGroups.filter((channel) => !channelGroupsForAnnouncement.includes(channel)));
887+
channelsForAnnouncement.push(...heartbeat.channels.filter((channel) => !channelsForAnnouncement.includes(channel)));
882888
}
883889
hbRequestsBySubscriptionKey[heartbeatRequestKey].channels = channelsForAnnouncement;
884890
hbRequestsBySubscriptionKey[heartbeatRequestKey].channelGroups = channelGroupsForAnnouncement;
@@ -1231,6 +1237,7 @@
12311237
subscriptionKey: event.subscriptionKey,
12321238
userId: event.userId,
12331239
heartbeatInterval: event.heartbeatInterval,
1240+
newlyRegistered: true,
12341241
logVerbosity: event.logVerbosity,
12351242
offlineClientsCheckInterval: event.workerOfflineClientsCheckInterval,
12361243
unsubscribeOfflineClients: event.workerUnsubscribeOfflineClients,
@@ -1330,7 +1337,8 @@
13301337
subscription.channelGroupQuery = channelGroupQuery;
13311338
subscription.channelGroups = channelGroupsFromRequest(event.request);
13321339
}
1333-
const { authKey, userId } = client;
1340+
let { authKey } = client;
1341+
const { userId } = client;
13341342
subscription.request = event.request;
13351343
subscription.filterExpression = ((_j = query['filter-expr']) !== null && _j !== void 0 ? _j : '');
13361344
subscription.timetoken = ((_k = query.tt) !== null && _k !== void 0 ? _k : '0');
@@ -1341,6 +1349,9 @@
13411349
client.userId = query.uuid;
13421350
client.pnsdk = query.pnsdk;
13431351
client.accessToken = event.token;
1352+
if (client.newlyRegistered && !authKey && client.authKey)
1353+
authKey = client.authKey;
1354+
client.newlyRegistered = false;
13441355
handleClientIdentityChangeIfRequired(client, userId, authKey);
13451356
};
13461357
/**

dist/web/pubnub.worker.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/core/components/configuration.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ const makeConfiguration = (base, setupCryptoModule) => {
124124
return base.PubNubFile;
125125
},
126126
get version() {
127-
return '9.2.0';
127+
return '9.3.0';
128128
},
129129
getVersion() {
130130
return this.version;

lib/core/interfaces/configuration.js

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -91,9 +91,9 @@ const FILE_REQUEST_TIMEOUT = 300;
9191
*/
9292
const PRESENCE_TIMEOUT = 300;
9393
/**
94-
* Minimum user presence timeout.
94+
* Maximum user presence timeout.
9595
*/
96-
const PRESENCE_TIMEOUT_MINIMUM = 20;
96+
const PRESENCE_TIMEOUT_MAXIMUM = 320;
9797
/**
9898
* Apply configuration default values.
9999
*
@@ -134,10 +134,17 @@ const setDefaults = (configuration) => {
134134
publishKey: configurationCopy.publishKey,
135135
secretKey: configurationCopy.secretKey,
136136
};
137-
if (configurationCopy.presenceTimeout !== undefined && configurationCopy.presenceTimeout < PRESENCE_TIMEOUT_MINIMUM) {
138-
configurationCopy.presenceTimeout = PRESENCE_TIMEOUT_MINIMUM;
139-
// eslint-disable-next-line no-console
140-
console.log('WARNING: Presence timeout is less than the minimum. Using minimum value: ', PRESENCE_TIMEOUT_MINIMUM);
137+
if (configurationCopy.presenceTimeout !== undefined) {
138+
if (configurationCopy.presenceTimeout > PRESENCE_TIMEOUT_MAXIMUM) {
139+
configurationCopy.presenceTimeout = PRESENCE_TIMEOUT_MAXIMUM;
140+
// eslint-disable-next-line no-console
141+
console.warn('WARNING: Presence timeout is larger than the maximum. Using maximum value: ', PRESENCE_TIMEOUT_MAXIMUM);
142+
}
143+
else if (configurationCopy.presenceTimeout <= 0) {
144+
// eslint-disable-next-line no-console
145+
console.warn('WARNING: Presence timeout should be larger than zero.');
146+
delete configurationCopy.presenceTimeout;
147+
}
141148
}
142149
if (configurationCopy.presenceTimeout !== undefined)
143150
configurationCopy.heartbeatInterval = configurationCopy.presenceTimeout / 2 - 1;

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "pubnub",
3-
"version": "9.2.0",
3+
"version": "9.3.0",
44
"author": "PubNub <[email protected]>",
55
"description": "Publish & Subscribe Real-time Messaging with PubNub",
66
"scripts": {

src/core/components/configuration.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ export const makeConfiguration = (
182182
return base.PubNubFile;
183183
},
184184
get version(): string {
185-
return '9.2.0';
185+
return '9.3.0';
186186
},
187187
getVersion(): string {
188188
return this.version;

src/core/interfaces/configuration.ts

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -115,9 +115,9 @@ const FILE_REQUEST_TIMEOUT = 300;
115115
const PRESENCE_TIMEOUT = 300;
116116

117117
/**
118-
* Minimum user presence timeout.
118+
* Maximum user presence timeout.
119119
*/
120-
const PRESENCE_TIMEOUT_MINIMUM = 20;
120+
const PRESENCE_TIMEOUT_MAXIMUM = 320;
121121
// endregion
122122

123123
/**
@@ -786,10 +786,19 @@ export const setDefaults = (configuration: UserConfiguration): ExtendedConfigura
786786
secretKey: configurationCopy.secretKey,
787787
};
788788

789-
if (configurationCopy.presenceTimeout !== undefined && configurationCopy.presenceTimeout < PRESENCE_TIMEOUT_MINIMUM) {
790-
configurationCopy.presenceTimeout = PRESENCE_TIMEOUT_MINIMUM;
791-
// eslint-disable-next-line no-console
792-
console.log('WARNING: Presence timeout is less than the minimum. Using minimum value: ', PRESENCE_TIMEOUT_MINIMUM);
789+
if (configurationCopy.presenceTimeout !== undefined) {
790+
if (configurationCopy.presenceTimeout > PRESENCE_TIMEOUT_MAXIMUM) {
791+
configurationCopy.presenceTimeout = PRESENCE_TIMEOUT_MAXIMUM;
792+
// eslint-disable-next-line no-console
793+
console.warn(
794+
'WARNING: Presence timeout is larger than the maximum. Using maximum value: ',
795+
PRESENCE_TIMEOUT_MAXIMUM,
796+
);
797+
} else if (configurationCopy.presenceTimeout <= 0) {
798+
// eslint-disable-next-line no-console
799+
console.warn('WARNING: Presence timeout should be larger than zero.');
800+
delete configurationCopy.presenceTimeout;
801+
}
793802
}
794803

795804
if (configurationCopy.presenceTimeout !== undefined)

0 commit comments

Comments
 (0)