Skip to content

Commit b9759e2

Browse files
author
Sunita Prajapati
committed
feat: fixed session_ID issue
- added unit test cases - refactored plugin code to be in sync with swift code
1 parent 409f954 commit b9759e2

File tree

2 files changed

+899
-34
lines changed

2 files changed

+899
-34
lines changed

packages/plugins/plugin-amplitudeSession/src/AmplitudeSessionPlugin.tsx

Lines changed: 176 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import {
1616
import AsyncStorage from '@react-native-async-storage/async-storage';
1717
import { AppState } from 'react-native';
1818

19-
const MAX_SESSION_TIME_IN_MS = 300000;
19+
const MAX_SESSION_TIME_IN_MS = 60000;
2020
const SESSION_ID_KEY = 'previous_session_id';
2121
const LAST_EVENT_TIME_KEY = 'last_event_time';
2222
const AMP_SESSION_START_EVENT = 'session_start';
@@ -28,37 +28,45 @@ export class AmplitudeSessionPlugin extends EventPlugin {
2828
active = false;
2929
sessionId = -1;
3030
lastEventTime = -1;
31+
eventSessionId = -1;
32+
resetPending = false;
33+
//private sessionCreationInProgress = false;
3134

3235
configure = async (analytics: SegmentClient): Promise<void> => {
36+
console.log('configure');
3337
this.analytics = analytics;
3438
await this.loadSessionData();
3539
AppState.addEventListener('change', this.handleAppStateChange);
3640
};
3741

3842
update(settings: SegmentAPISettings, type: UpdateType) {
39-
if (type !== UpdateType.initial) {
40-
return;
41-
}
43+
console.log('update');
44+
45+
if (type !== UpdateType.initial) return;
4246
this.active = settings.integrations?.hasOwnProperty(this.key) ?? false;
4347
}
4448

4549
async execute(event: SegmentEvent) {
46-
if (!this.active) {
47-
return event;
48-
}
50+
console.log('execute');
51+
52+
if (!this.active) return event;
4953

5054
if (this.sessionId === -1 || this.lastEventTime === -1) {
55+
console.log('execute loadSessionData');
5156
await this.loadSessionData();
5257
}
53-
58+
console.log('execute startNewSessionIfNecessary');
5459
await this.startNewSessionIfNecessary();
5560

61+
62+
5663
let result = event;
5764
switch (result.type) {
5865
case EventType.IdentifyEvent:
5966
result = this.identify(result);
6067
break;
6168
case EventType.TrackEvent:
69+
console.log('EventType.TrackEvent');
6270
result = this.track(result);
6371
break;
6472
case EventType.ScreenEvent:
@@ -73,8 +81,9 @@ export class AmplitudeSessionPlugin extends EventPlugin {
7381
}
7482

7583
this.lastEventTime = Date.now();
76-
await this.saveSessionData();
84+
console.log('execute saveSessionData');
7785

86+
await this.saveSessionData();
7887
return result;
7988
}
8089

@@ -83,6 +92,35 @@ export class AmplitudeSessionPlugin extends EventPlugin {
8392
}
8493

8594
track(event: TrackEventType) {
95+
const eventName = event.event;
96+
console.log('event',eventName);
97+
98+
if (eventName === AMP_SESSION_START_EVENT) {
99+
console.log('track Session_Start');
100+
this.resetPending = false;
101+
this.eventSessionId = this.sessionId;
102+
console.log(`[AmplitudeSession] NewSession = ${this.eventSessionId}`);
103+
}
104+
105+
if (eventName === AMP_SESSION_END_EVENT) {
106+
console.log(`[AmplitudeSession] EndSession = ${this.eventSessionId}`);
107+
}
108+
109+
if (
110+
eventName.startsWith('Amplitude') ||
111+
eventName === AMP_SESSION_START_EVENT ||
112+
eventName === AMP_SESSION_END_EVENT
113+
) {
114+
const integrations = this.disableAllIntegrations(event.integrations);
115+
return {
116+
...event,
117+
integrations: {
118+
...integrations,
119+
[this.key]: { session_id: this.eventSessionId },
120+
},
121+
};
122+
}
123+
86124
return this.insertSession(event) as TrackEventType;
87125
}
88126

@@ -139,43 +177,132 @@ export class AmplitudeSessionPlugin extends EventPlugin {
139177
this.startNewSessionIfNecessary();
140178
};
141179

180+
// private async startNewSessionIfNecessary() {
181+
// if (this.eventSessionId === -1) {
182+
// this.eventSessionId = this.sessionId;
183+
// }
184+
185+
// if (this.resetPending) return;
186+
187+
// const current = Date.now();
188+
// const withinSessionLimit = this.withinMinSessionTime(current);
189+
// console.log('withinSessionLimit', withinSessionLimit);
190+
// const isSessionExpired = this.sessionId === -1 || this.lastEventTime === -1 || !withinSessionLimit;
191+
// console.log('isSessionExpired', isSessionExpired);
192+
193+
// if (this.sessionId >= 0 && !isSessionExpired) {
194+
// this.lastEventTime = current;
195+
// await this.saveSessionData();
196+
// return; // same session, nothing to do
197+
// }
198+
// const oldSessionId = this.sessionId;
199+
// await this.endSession(oldSessionId);
200+
// this.lastEventTime = current;
201+
// await this.saveSessionData();
202+
203+
204+
// await this.startNewSession();
205+
// }
206+
207+
// private async startNewSession() {
208+
// if (this.resetPending) return;
209+
210+
// this.resetPending = true;
211+
// this.sessionId = Date.now();
212+
213+
// if (this.eventSessionId === -1) {
214+
// this.eventSessionId = this.sessionId;
215+
// }
216+
217+
// this.lastEventTime = this.sessionId;
218+
// await this.saveSessionData();
219+
220+
// console.log(`[AmplitudeSession] startNewSession -> ${this.sessionId}`);
221+
// this.analytics?.track(AMP_SESSION_START_EVENT, {
222+
// integrations: {
223+
// [this.key]: { session_id: this.sessionId },
224+
// },
225+
// });
226+
// }
227+
142228
private async startNewSessionIfNecessary() {
143-
const current = Date.now();
229+
if (this.eventSessionId === -1) {
230+
this.eventSessionId = this.sessionId;
231+
}
144232

145-
const sessionExpired =
146-
this.sessionId === -1 ||
147-
this.lastEventTime === -1 ||
148-
current - this.lastEventTime >= MAX_SESSION_TIME_IN_MS;
233+
if (this.resetPending) return;
149234

150-
// Avoid loop: if session just started recently, skip restarting
151-
if (!sessionExpired || current - this.sessionId < 1000) {
152-
return;
153-
}
235+
const current = Date.now();
236+
const withinSessionLimit = this.withinMinSessionTime(current);
237+
console.log('withinSessionLimit', withinSessionLimit);
154238

155-
await this.endSession();
156-
await this.startNewSession();
157-
}
239+
const isSessionExpired =
240+
this.sessionId === -1 ||
241+
this.lastEventTime === -1 ||
242+
!withinSessionLimit;
243+
244+
console.log('isSessionExpired', isSessionExpired);
245+
this.lastEventTime = current;
158246

159-
private async startNewSession() {
160-
this.sessionId = Date.now();
161-
this.lastEventTime = this.sessionId;
247+
if (this.sessionId >= 0 && !isSessionExpired) {
248+
// Continue current session
249+
162250
await this.saveSessionData();
251+
return;
252+
}
163253

164-
this.analytics?.track(AMP_SESSION_START_EVENT, {
165-
integrations: {
166-
[this.key]: { session_id: this.sessionId },
167-
},
168-
});
254+
// End old session and start a new one
255+
await this.startNewSession();
256+
}
257+
258+
/**
259+
* Handles the entire process of starting a new session.
260+
* Can be called directly or from startNewSessionIfNecessary()
261+
*/
262+
private async startNewSession() {
263+
if (this.resetPending) return;
264+
265+
this.resetPending = true;
266+
267+
const oldSessionId = this.sessionId;
268+
if (oldSessionId >= 0) {
269+
await this.endSession(oldSessionId);
169270
}
170271

171-
private async endSession() {
172-
if (this.sessionId === -1) {
173-
return;
174-
}
272+
const newSessionId = Date.now();
273+
this.sessionId = newSessionId;
274+
this.eventSessionId = this.eventSessionId === -1 ? newSessionId : this.eventSessionId;
275+
this.lastEventTime = newSessionId;
276+
277+
await this.saveSessionData();
278+
279+
console.log(`[AmplitudeSession] startNewSession -> ${newSessionId}`);
280+
281+
await this.trackSessionStart(newSessionId);
282+
283+
//this.resetPending = false;
284+
}
285+
286+
/**
287+
* Extracted analytics tracking into its own method
288+
*/
289+
private async trackSessionStart(sessionId: number) {
290+
this.analytics?.track(AMP_SESSION_START_EVENT, {
291+
integrations: {
292+
[this.key]: { session_id: sessionId },
293+
},
294+
});
295+
}
296+
297+
298+
private async endSession(sessionId: number) {
299+
if (this.sessionId === -1) return;
300+
301+
console.log(`[AmplitudeSession] endSession -> ${this.sessionId}`);
175302

176303
this.analytics?.track(AMP_SESSION_END_EVENT, {
177304
integrations: {
178-
[this.key]: { session_id: this.sessionId },
305+
[this.key]: { session_id: sessionId },
179306
},
180307
});
181308
}
@@ -196,6 +323,20 @@ export class AmplitudeSessionPlugin extends EventPlugin {
196323
);
197324
}
198325

326+
private disableAllIntegrations(integrations?: Record<string, any>) {
327+
const result: Record<string, any> = {};
328+
if (!integrations) return result;
329+
for (const key of Object.keys(integrations)) {
330+
result[key] = false;
331+
}
332+
return result;
333+
}
334+
335+
private withinMinSessionTime(timestamp: number): boolean {
336+
const timeDelta = timestamp - this.lastEventTime;
337+
return timeDelta < MAX_SESSION_TIME_IN_MS ;
338+
}
339+
199340
private handleAppStateChange = (nextAppState: string) => {
200341
if (nextAppState === 'active') {
201342
this.onForeground();
@@ -204,3 +345,4 @@ export class AmplitudeSessionPlugin extends EventPlugin {
204345
}
205346
};
206347
}
348+

0 commit comments

Comments
 (0)