Skip to content

refactor: for session_id #1080

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jun 26, 2025
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
139 changes: 116 additions & 23 deletions packages/plugins/plugin-amplitudeSession/src/AmplitudeSessionPlugin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,32 +10,56 @@ import {
GroupEventType,
UpdateType,
AliasEventType,
SegmentClient,
} from '@segment/analytics-react-native';

import AsyncStorage from '@react-native-async-storage/async-storage';
import { AppState } from 'react-native';
//import { AppState } from 'react-native';

const MAX_SESSION_TIME_IN_MS = 300000;
const SESSION_ID_KEY = 'previous_session_id';
const LAST_EVENT_TIME_KEY = 'last_event_time';
const AMP_SESSION_START_EVENT = 'session_start';
const AMP_SESSION_END_EVENT = 'session_end';

export class AmplitudeSessionPlugin extends EventPlugin {
type = PluginType.enrichment;
key = 'Actions Amplitude';
active = false;
sessionId: number | undefined;
sessionId = -1;
lastEventTime = -1;
sessionTimer: ReturnType<typeof setTimeout> | undefined;

update(settings: SegmentAPISettings, _: UpdateType) {
const integrations = settings.integrations;
if (this.key in integrations) {
this.active = true;
this.refreshSession();
configure(analytics: SegmentClient): void {
this.analytics = analytics;
AppState.addEventListener('change', this.handleAppStateChange);
this.loadSessionData();
if (this.sessionId === -1) {
this.startNewSession();
} else {
this.startNewSessionIfNecessary();
}
}

update(settings: SegmentAPISettings, type: UpdateType) {
if (type !== UpdateType.initial) {
return;
}
this.active = settings.integrations?.hasOwnProperty(this.key) ?? false;
}

execute(event: SegmentEvent) {
async execute(event: SegmentEvent) {
if (!this.active) {
return event;
}

this.refreshSession();
await this.startNewSessionIfNecessary();

let result = event;
if (result.type === EventType.TrackEvent) {
console.log(result.event);
}

switch (result.type) {
case EventType.IdentifyEvent:
result = this.identify(result);
Expand All @@ -53,6 +77,10 @@ export class AmplitudeSessionPlugin extends EventPlugin {
result = this.group(result);
break;
}

this.lastEventTime = Date.now();
await this.saveSessionData();

return result;
}

Expand All @@ -65,6 +93,10 @@ export class AmplitudeSessionPlugin extends EventPlugin {
}

screen(event: ScreenEventType) {
event.properties = {
...event.properties,
name: event.name,
};
return this.insertSession(event) as ScreenEventType;
}

Expand All @@ -77,12 +109,23 @@ export class AmplitudeSessionPlugin extends EventPlugin {
}

reset() {
this.resetSession();
//this.resetSession();
}

private insertSession = (event: SegmentEvent) => {
const returnEvent = event;
const integrations = event.integrations;
const integrations = event.integrations || {};
const existingIntegration = integrations[this.key];
const hasSessionId =
typeof existingIntegration === 'object' &&
existingIntegration !== null &&
'session_id' in existingIntegration;

// If session_id exists, return as is
if (hasSessionId) {
return returnEvent;
}

returnEvent.integrations = {
...integrations,
[this.key]: {
Expand All @@ -92,23 +135,73 @@ export class AmplitudeSessionPlugin extends EventPlugin {
return returnEvent;
};

private resetSession = () => {
this.sessionId = Date.now();
this.sessionTimer = undefined;
};
private onBackground() {
this.lastEventTime = Date.now();

private refreshSession = () => {
if (this.sessionId === undefined) {
this.sessionId = Date.now();
this.saveSessionData();
}

private onForeground() {
this.startNewSessionIfNecessary();
}

private async startNewSessionIfNecessary() {
const current = Date.now();
const withinSessionLimit =
current - this.lastEventTime < MAX_SESSION_TIME_IN_MS;
if (this.sessionId >= 0 && withinSessionLimit) {
return;
}
this.lastEventTime = current;
await this.endSession();
await this.startNewSession();
}

if (this.sessionTimer !== undefined) {
clearTimeout(this.sessionTimer);
private async startNewSession() {
this.sessionId = Date.now();
const copy = this.sessionId;
if (this.analytics) {
this.analytics.track(AMP_SESSION_START_EVENT, {
integrations: {
[this.key]: { session_id: copy },
},
});
}
await this.saveSessionData();
}

this.sessionTimer = setTimeout(
() => this.resetSession(),
MAX_SESSION_TIME_IN_MS
private async endSession() {
const copy = this.sessionId;
if (this.analytics) {
this.analytics.track(AMP_SESSION_END_EVENT, {
integrations: {
[this.key]: { session_id: copy },
},
});
}
}

private async loadSessionData() {
const storedSessionId = await AsyncStorage.getItem(SESSION_ID_KEY);
const storedLastEventTime = await AsyncStorage.getItem(LAST_EVENT_TIME_KEY);
this.sessionId = storedSessionId != null ? Number(storedSessionId) : -1;
this.lastEventTime =
storedLastEventTime != null ? Number(storedLastEventTime) : -1;
}

private async saveSessionData() {
await AsyncStorage.setItem(SESSION_ID_KEY, this.sessionId.toString());
await AsyncStorage.setItem(
LAST_EVENT_TIME_KEY,
this.lastEventTime.toString()
);
}

private handleAppStateChange = (nextAppState: string) => {
if (nextAppState === 'active') {
this.onForeground();
} else if (nextAppState === 'background') {
this.onBackground();
}
};
}
Loading