{"version":3,"file":"sessionflusher.js","sources":["../../src/sessionflusher.ts"],"sourcesContent":["import type {\n AggregationCounts,\n Client,\n RequestSessionStatus,\n SessionAggregates,\n SessionFlusherLike,\n} from '@sentry/types';\nimport { dropUndefinedKeys } from '@sentry/utils';\nimport { getIsolationScope } from './currentScopes';\n\ntype ReleaseHealthAttributes = {\n environment?: string;\n release: string;\n};\n\n/**\n * @inheritdoc\n */\nexport class SessionFlusher implements SessionFlusherLike {\n public readonly flushTimeout: number;\n private _pendingAggregates: Map;\n private _sessionAttrs: ReleaseHealthAttributes;\n // Cast to any so that it can use Node.js timeout\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private _intervalId: any;\n private _isEnabled: boolean;\n private _client: Client;\n\n public constructor(client: Client, attrs: ReleaseHealthAttributes) {\n this._client = client;\n this.flushTimeout = 60;\n this._pendingAggregates = new Map();\n this._isEnabled = true;\n\n // Call to setInterval, so that flush is called every 60 seconds.\n this._intervalId = setInterval(() => this.flush(), this.flushTimeout * 1000);\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n if (this._intervalId.unref) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n this._intervalId.unref();\n }\n this._sessionAttrs = attrs;\n }\n\n /** Checks if `pendingAggregates` has entries, and if it does flushes them by calling `sendSession` */\n public flush(): void {\n const sessionAggregates = this.getSessionAggregates();\n if (sessionAggregates.aggregates.length === 0) {\n return;\n }\n this._pendingAggregates = new Map();\n this._client.sendSession(sessionAggregates);\n }\n\n /** Massages the entries in `pendingAggregates` and returns aggregated sessions */\n public getSessionAggregates(): SessionAggregates {\n const aggregates: AggregationCounts[] = Array.from(this._pendingAggregates.values());\n\n const sessionAggregates: SessionAggregates = {\n attrs: this._sessionAttrs,\n aggregates,\n };\n return dropUndefinedKeys(sessionAggregates);\n }\n\n /** JSDoc */\n public close(): void {\n clearInterval(this._intervalId);\n this._isEnabled = false;\n this.flush();\n }\n\n /**\n * Wrapper function for _incrementSessionStatusCount that checks if the instance of SessionFlusher is enabled then\n * fetches the session status of the request from `Scope.getRequestSession().status` on the scope and passes them to\n * `_incrementSessionStatusCount` along with the start date\n */\n public incrementSessionStatusCount(): void {\n if (!this._isEnabled) {\n return;\n }\n const isolationScope = getIsolationScope();\n const requestSession = isolationScope.getRequestSession();\n\n if (requestSession && requestSession.status) {\n this._incrementSessionStatusCount(requestSession.status, new Date());\n // This is not entirely necessarily but is added as a safe guard to indicate the bounds of a request and so in\n // case captureRequestSession is called more than once to prevent double count\n isolationScope.setRequestSession(undefined);\n /* eslint-enable @typescript-eslint/no-unsafe-member-access */\n }\n }\n\n /**\n * Increments status bucket in pendingAggregates buffer (internal state) corresponding to status of\n * the session received\n */\n private _incrementSessionStatusCount(status: RequestSessionStatus, date: Date): number {\n // Truncate minutes and seconds on Session Started attribute to have one minute bucket keys\n const sessionStartedTrunc = new Date(date).setSeconds(0, 0);\n\n // corresponds to aggregated sessions in one specific minute bucket\n // for example, {\"started\":\"2021-03-16T08:00:00.000Z\",\"exited\":4, \"errored\": 1}\n let aggregationCounts = this._pendingAggregates.get(sessionStartedTrunc);\n if (!aggregationCounts) {\n aggregationCounts = { started: new Date(sessionStartedTrunc).toISOString() };\n this._pendingAggregates.set(sessionStartedTrunc, aggregationCounts);\n }\n\n switch (status) {\n case 'errored':\n aggregationCounts.errored = (aggregationCounts.errored || 0) + 1;\n return aggregationCounts.errored;\n case 'ok':\n aggregationCounts.exited = (aggregationCounts.exited || 0) + 1;\n return aggregationCounts.exited;\n default:\n aggregationCounts.crashed = (aggregationCounts.crashed || 0) + 1;\n return aggregationCounts.crashed;\n }\n }\n}\n"],"names":[],"mappings":"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"}