Skip to content

Commit

Permalink
feat: add _experimental_longtaskNoStartSession flag
Browse files Browse the repository at this point in the history
  • Loading branch information
Joozty committed Dec 3, 2024
1 parent 34e0f4c commit 047fdf8
Showing 1 changed file with 36 additions and 16 deletions.
52 changes: 36 additions & 16 deletions packages/web/src/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,10 @@ import { cookieStore, findCookieValue, generateId, isIframe } from './utils'
with setting cookies, checking for inactivity, etc.
*/

const MaxSessionAgeMillis = 4 * 60 * 60 * 1000
const InactivityTimeoutSeconds = 15 * 60
const PeriodicCheckSeconds = 60
const MaxSessionAgeSeconds = 4 * 60 * 60
const MaxSessionAgeMillis = MaxSessionAgeSeconds * 1000
const InactivityTimeoutMillis = 15 * 60 * 1000

export const COOKIE_NAME = '_splunk_rum_sid'

export type SessionIdType = string
Expand All @@ -59,7 +60,18 @@ function pastMaxAge(startTime: number): boolean {
return startTime > now || now > startTime + MaxSessionAgeMillis
}

export function parseCookieToSessionState(): { id: string; startTime: number } | undefined {
function pastExpirationTime(expirationTime: number): boolean {
const now = Date.now()
return expirationTime < now + InactivityTimeoutMillis
}

interface CookieState {
expirationTime?: number
id: string
startTime: number
}

export function parseCookieToSessionState(): CookieState | undefined {
const rawValue = findCookieValue(COOKIE_NAME)
if (!rawValue) {
return undefined
Expand All @@ -70,7 +82,7 @@ export function parseCookieToSessionState(): { id: string; startTime: number } |
return undefined
}

let ss: { id: string; startTime: number } | undefined = undefined
let ss: CookieState | undefined = undefined
try {
ss = JSON.parse(decoded)
} catch {
Expand All @@ -91,25 +103,30 @@ export function parseCookieToSessionState(): { id: string; startTime: number } |
return undefined
}

if ('expirationTime' in ss && typeof ss.expirationTime === 'number' && pastExpirationTime(ss.expirationTime)) {
return undefined
}

return ss
}

function newSessionState() {
function newSessionState(): CookieState {
return {
id: generateId(128),
startTime: Date.now(),
expirationTime: Date.now() + InactivityTimeoutMillis,
}
}

function renewCookieTimeout(sessionState) {
function updateCookie(sessionState: CookieState) {
if (pastMaxAge(sessionState.startTime)) {
// safety valve
return
}

const cookieValue = encodeURIComponent(JSON.stringify(sessionState))
const domain = cookieDomain ? `domain=${cookieDomain};` : ''
let cookie = COOKIE_NAME + '=' + cookieValue + '; path=/;' + domain + 'max-age=' + InactivityTimeoutSeconds
let cookie = COOKIE_NAME + '=' + cookieValue + '; path=/;' + domain + 'max-age=' + MaxSessionAgeSeconds

if (isIframe()) {
cookie += ';SameSite=None; Secure'
Expand Down Expand Up @@ -141,7 +158,8 @@ export function updateSessionStatus(): void {
eventTarget?.emit('session-changed', { sessionId: rumSessionId })

if (recentActivity) {
renewCookieTimeout(sessionState)
sessionState.expirationTime = Date.now() + InactivityTimeoutMillis
updateCookie(sessionState)
}

recentActivity = false
Expand All @@ -151,15 +169,21 @@ function hasNativeSessionId(): boolean {
return typeof window !== 'undefined' && window['SplunkRumNative'] && window['SplunkRumNative'].getNativeSessionId
}

class ActivitySpanProcessor implements SpanProcessor {
class SessionSpanProcessor implements SpanProcessor {
constructor(private readonly allSpansAreActivity: boolean) {}

forceFlush(): Promise<void> {
return Promise.resolve()
}

onEnd(): void {}

onStart(): void {
markActivity()
if (this.allSpansAreActivity) {
markActivity()
}

updateSessionStatus()
}

shutdown(): Promise<void> {
Expand Down Expand Up @@ -194,17 +218,13 @@ export function initSessionTracking(
eventTarget = newEventTarget

ACTIVITY_EVENTS.forEach((type) => document.addEventListener(type, markActivity, { capture: true, passive: true }))
if (allSpansAreActivity) {
provider.addSpanProcessor(new ActivitySpanProcessor())
}
provider.addSpanProcessor(new SessionSpanProcessor(allSpansAreActivity))

updateSessionStatus()
const intervalHandle = setInterval(() => updateSessionStatus(), PeriodicCheckSeconds * 1000)

return {
deinit: () => {
ACTIVITY_EVENTS.forEach((type) => document.removeEventListener(type, markActivity))
clearInterval(intervalHandle)
rumSessionId = undefined
eventTarget = undefined
},
Expand Down

0 comments on commit 047fdf8

Please sign in to comment.