From 5561bdfd359170af1061361ff521b475f26278e3 Mon Sep 17 00:00:00 2001 From: Radu Berinde Date: Wed, 15 Feb 2023 19:25:30 -0800 Subject: [PATCH 1/2] go.mod: bump Pebble to 9b1142a5070e 9b1142a5 db: add ErrorIfNotPristine option fbbc39d1 sstable: add readahead for value blocks Release note: --- DEPS.bzl | 6 +++--- build/bazelutil/distdir_files.bzl | 2 +- go.mod | 2 +- go.sum | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/DEPS.bzl b/DEPS.bzl index bcd8abb7db61..e55bb05c0675 100644 --- a/DEPS.bzl +++ b/DEPS.bzl @@ -1555,10 +1555,10 @@ def go_deps(): patches = [ "@com_github_cockroachdb_cockroach//build/patches:com_github_cockroachdb_pebble.patch", ], - sha256 = "827af6eb58999bd80dd1ffc82a45697d1047dc3edd8c04563dd5e2e8264cec17", - strip_prefix = "github.com/cockroachdb/pebble@v0.0.0-20230215164001-c99dee64598f", + sha256 = "84df44fb4599cf685813a830093a9db1c975c093fe095ec5144020aa7504d0c2", + strip_prefix = "github.com/cockroachdb/pebble@v0.0.0-20230216002728-9b1142a5070e", urls = [ - "https://storage.googleapis.com/cockroach-godeps/gomod/github.com/cockroachdb/pebble/com_github_cockroachdb_pebble-v0.0.0-20230215164001-c99dee64598f.zip", + "https://storage.googleapis.com/cockroach-godeps/gomod/github.com/cockroachdb/pebble/com_github_cockroachdb_pebble-v0.0.0-20230216002728-9b1142a5070e.zip", ], ) go_repository( diff --git a/build/bazelutil/distdir_files.bzl b/build/bazelutil/distdir_files.bzl index 8958fa6e3f0c..25143062b13d 100644 --- a/build/bazelutil/distdir_files.bzl +++ b/build/bazelutil/distdir_files.bzl @@ -202,7 +202,7 @@ DISTDIR_FILES = { "https://storage.googleapis.com/cockroach-godeps/gomod/github.com/cockroachdb/google-api-go-client/com_github_cockroachdb_google_api_go_client-v0.80.1-0.20221117193156-6a9f7150cb93.zip": "b3378c579f4f4340403038305907d672c86f615f8233118a8873ebe4229c4f39", "https://storage.googleapis.com/cockroach-godeps/gomod/github.com/cockroachdb/gostdlib/com_github_cockroachdb_gostdlib-v1.19.0.zip": "c4d516bcfe8c07b6fc09b8a9a07a95065b36c2855627cb3514e40c98f872b69e", "https://storage.googleapis.com/cockroach-godeps/gomod/github.com/cockroachdb/logtags/com_github_cockroachdb_logtags-v0.0.0-20230118201751-21c54148d20b.zip": "ca7776f47e5fecb4c495490a679036bfc29d95bd7625290cfdb9abb0baf97476", - "https://storage.googleapis.com/cockroach-godeps/gomod/github.com/cockroachdb/pebble/com_github_cockroachdb_pebble-v0.0.0-20230215164001-c99dee64598f.zip": "827af6eb58999bd80dd1ffc82a45697d1047dc3edd8c04563dd5e2e8264cec17", + "https://storage.googleapis.com/cockroach-godeps/gomod/github.com/cockroachdb/pebble/com_github_cockroachdb_pebble-v0.0.0-20230216002728-9b1142a5070e.zip": "84df44fb4599cf685813a830093a9db1c975c093fe095ec5144020aa7504d0c2", "https://storage.googleapis.com/cockroach-godeps/gomod/github.com/cockroachdb/redact/com_github_cockroachdb_redact-v1.1.3.zip": "7778b1e4485e4f17f35e5e592d87eb99c29e173ac9507801d000ad76dd0c261e", "https://storage.googleapis.com/cockroach-godeps/gomod/github.com/cockroachdb/returncheck/com_github_cockroachdb_returncheck-v0.0.0-20200612231554-92cdbca611dd.zip": "ce92ba4352deec995b1f2eecf16eba7f5d51f5aa245a1c362dfe24c83d31f82b", "https://storage.googleapis.com/cockroach-godeps/gomod/github.com/cockroachdb/sentry-go/com_github_cockroachdb_sentry_go-v0.6.1-cockroachdb.2.zip": "fbb2207d02aecfdd411b1357efe1192dbb827959e36b7cab7491731ac55935c9", diff --git a/go.mod b/go.mod index e7d85e05e3c7..fc9da3ce1443 100644 --- a/go.mod +++ b/go.mod @@ -114,7 +114,7 @@ require ( github.com/cockroachdb/go-test-teamcity v0.0.0-20191211140407-cff980ad0a55 github.com/cockroachdb/gostdlib v1.19.0 github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b - github.com/cockroachdb/pebble v0.0.0-20230215164001-c99dee64598f + github.com/cockroachdb/pebble v0.0.0-20230216002728-9b1142a5070e github.com/cockroachdb/redact v1.1.3 github.com/cockroachdb/returncheck v0.0.0-20200612231554-92cdbca611dd github.com/cockroachdb/stress v0.0.0-20220803192808-1806698b1b7b diff --git a/go.sum b/go.sum index f4bc7b7ab83a..846dc97471ec 100644 --- a/go.sum +++ b/go.sum @@ -492,8 +492,8 @@ github.com/cockroachdb/gostdlib v1.19.0/go.mod h1:+dqqpARXbE/gRDEhCak6dm0l14AaTy github.com/cockroachdb/logtags v0.0.0-20211118104740-dabe8e521a4f/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= -github.com/cockroachdb/pebble v0.0.0-20230215164001-c99dee64598f h1:y9LPHH46jWopzFm67GWacLdIgsiALGqPgHjD1cysZSM= -github.com/cockroachdb/pebble v0.0.0-20230215164001-c99dee64598f/go.mod h1:9lRMC4XN3/BLPtIp6kAKwIaHu369NOf2rMucPzipz50= +github.com/cockroachdb/pebble v0.0.0-20230216002728-9b1142a5070e h1:++hK+cy7bPIqlvaZDA3zPcwY+m//toJGKqgzWaQjVzI= +github.com/cockroachdb/pebble v0.0.0-20230216002728-9b1142a5070e/go.mod h1:9lRMC4XN3/BLPtIp6kAKwIaHu369NOf2rMucPzipz50= github.com/cockroachdb/redact v1.1.3 h1:AKZds10rFSIj7qADf0g46UixK8NNLwWTNdCIGS5wfSQ= github.com/cockroachdb/redact v1.1.3/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= github.com/cockroachdb/returncheck v0.0.0-20200612231554-92cdbca611dd h1:KFOt5I9nEKZgCnOSmy8r4Oykh8BYQO8bFOTgHDS8YZA= From a6fd886eccd5a0432a8465b1274cb0f10edc49a4 Mon Sep 17 00:00:00 2001 From: maryliag Date: Tue, 14 Feb 2023 20:07:09 -0500 Subject: [PATCH 2/2] ui: show data when max size reached Previously, when the sql api returned a max size reached error, we were just showing the error, but not the data that was also being returned. This PR creates a new function to format the return of the api calls, so when is a max size error it doesn't throw an error, but still pass that info so we can display a warning on the pages. This commit updates the Insights Workload > Statement page with the new behaviour. Following PRs will update other usages of the sql api. Part Of: #96184 Release note (ui change): Still show data on the console (with a warning) for Statement Insights when we reach a "max size exceed" error from the sql api. --- .../workspaces/cluster-ui/src/api/sqlApi.ts | 30 +++++++++++++++++++ .../cluster-ui/src/api/stmtInsightsApi.ts | 21 ++++++------- .../statementInsightDetails.tsx | 2 +- .../statementInsightsView.tsx | 19 ++++++++++++ .../workloadInsightsPageConnected.tsx | 2 ++ .../statementFingerprintInsights.reducer.ts | 6 ++-- .../statementFingerprintInsights.selectors.ts | 2 +- .../statementInsights.reducer.ts | 6 ++-- .../statementInsights.selectors.ts | 5 +++- .../db-console/src/redux/apiReducers.ts | 8 +++-- .../src/views/insights/insightsSelectors.ts | 15 ++++++++-- .../views/insights/workloadInsightsPage.tsx | 2 ++ .../src/views/statements/statementDetails.tsx | 2 +- 13 files changed, 94 insertions(+), 26 deletions(-) diff --git a/pkg/ui/workspaces/cluster-ui/src/api/sqlApi.ts b/pkg/ui/workspaces/cluster-ui/src/api/sqlApi.ts index 3fafc43c6c17..7c40acf12537 100644 --- a/pkg/ui/workspaces/cluster-ui/src/api/sqlApi.ts +++ b/pkg/ui/workspaces/cluster-ui/src/api/sqlApi.ts @@ -60,6 +60,11 @@ export type SqlExecutionErrorMessage = { source: { file: string; line: number; function: "string" }; }; +export type ApiResponse = { + maxSizeReached: boolean; + results: Array; +}; + export const SQL_API_PATH = "/api/v2/sql/"; /** @@ -159,3 +164,28 @@ export function sqlApiErrorMessage(message: string): string { return message; } + +function isMaxSizeError(message: string): boolean { + return !!message?.includes("max result size exceeded"); +} + +export function formatApiResult( + results: Array, + error: SqlExecutionErrorMessage, + errorMessageContext: string, +): ApiResponse { + const maxSizeError = isMaxSizeError(error?.message); + + if (error && !maxSizeError) { + throw new Error( + `Error while ${errorMessageContext}: ${sqlApiErrorMessage( + error?.message, + )}`, + ); + } + + return { + maxSizeReached: maxSizeError, + results: results, + }; +} diff --git a/pkg/ui/workspaces/cluster-ui/src/api/stmtInsightsApi.ts b/pkg/ui/workspaces/cluster-ui/src/api/stmtInsightsApi.ts index f35619149aaf..045eb9e6bd84 100644 --- a/pkg/ui/workspaces/cluster-ui/src/api/stmtInsightsApi.ts +++ b/pkg/ui/workspaces/cluster-ui/src/api/stmtInsightsApi.ts @@ -9,10 +9,11 @@ // licenses/APL.txt. import { + ApiResponse, executeInternalSql, + formatApiResult, LARGE_RESULT_SIZE, LONG_TIMEOUT, - sqlApiErrorMessage, SqlExecutionRequest, sqlResultsAreEmpty, SqlTxnResult, @@ -137,7 +138,7 @@ export const stmtInsightsByTxnExecutionQuery = (id: string): string => ` export async function getStmtInsightsApi( req?: StmtInsightsReq, -): Promise { +): Promise> { const request: SqlExecutionRequest = { statements: [ { @@ -150,21 +151,17 @@ export async function getStmtInsightsApi( }; const result = await executeInternalSql(request); - if (result.error) { - throw new Error( - `Error while retrieving insights information: ${sqlApiErrorMessage( - result.error.message, - )}`, - ); - } if (sqlResultsAreEmpty(result)) { - return []; + return formatApiResult([], result.error, "retrieving insights information"); } - const stmtInsightEvent = formatStmtInsights(result.execution?.txn_results[0]); await addStmtContentionInfoApi(stmtInsightEvent); - return stmtInsightEvent; + return formatApiResult( + stmtInsightEvent, + result.error, + "retrieving insights information", + ); } async function addStmtContentionInfoApi( diff --git a/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsightDetails/statementInsightDetails.tsx b/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsightDetails/statementInsightDetails.tsx index 50b9c7fbbc8d..f8abcf88e9cd 100644 --- a/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsightDetails/statementInsightDetails.tsx +++ b/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsightDetails/statementInsightDetails.tsx @@ -124,7 +124,7 @@ export const StatementInsightDetails: React.FC< getStmtInsightsApi({ stmtExecutionID: executionID, start, end }) .then(res => { setInsightDetails({ - details: res?.length ? res[0] : null, + details: res?.results?.length ? res.results[0] : null, loaded: true, }); }) diff --git a/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsights/statementInsights/statementInsightsView.tsx b/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsights/statementInsights/statementInsightsView.tsx index c43eae12da5e..a9b1518c9b8f 100644 --- a/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsights/statementInsights/statementInsightsView.tsx +++ b/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsights/statementInsights/statementInsightsView.tsx @@ -56,6 +56,9 @@ import styles from "src/statementsPage/statementsPage.module.scss"; import sortableTableStyles from "src/sortedtable/sortedtable.module.scss"; import { commonStyles } from "../../../common"; import { useFetchDataWithPolling } from "src/util/hooks"; +import { InlineAlert } from "@cockroachlabs/ui-components"; +import { insights } from "src/util"; +import { Anchor } from "src/anchor"; const cx = classNames.bind(styles); const sortableTableCx = classNames.bind(sortableTableStyles); @@ -72,6 +75,7 @@ export type StatementInsightsViewStateProps = { isLoading?: boolean; dropDownSelect?: React.ReactElement; timeScale?: TimeScale; + maxSizeApiReached?: boolean; }; export type StatementInsightsViewDispatchProps = { @@ -105,6 +109,7 @@ export const StatementInsightsView: React.FC = ({ setTimeScale, selectedColumnNames, dropDownSelect, + maxSizeApiReached, }: StatementInsightsViewProps) => { const [pagination, setPagination] = useState({ current: 1, @@ -317,6 +322,20 @@ export const StatementInsightsView: React.FC = ({ total={filteredStatements?.length} onChange={onChangePage} /> + {maxSizeApiReached && ( + + Not all insights are displayed because the maximum number of + insights was reached in the console.  + + Learn more + + + } + /> + )} diff --git a/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsights/workloadInsightsPageConnected.tsx b/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsights/workloadInsightsPageConnected.tsx index 6a1d7ddbe93c..51be49fe4a69 100644 --- a/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsights/workloadInsightsPageConnected.tsx +++ b/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsights/workloadInsightsPageConnected.tsx @@ -34,6 +34,7 @@ import { selectStmtInsights, selectStmtInsightsError, selectStmtInsightsLoading, + selectStmtInsightsMaxApiReached, } from "src/store/insights/statementInsights"; import { actions as txnInsights, @@ -78,6 +79,7 @@ const statementMapStateToProps = ( selectedColumnNames: selectColumns(state), timeScale: selectTimeScale(state), isLoading: selectStmtInsightsLoading(state), + maxSizeApiReached: selectStmtInsightsMaxApiReached(state), }); const TransactionDispatchProps = ( diff --git a/pkg/ui/workspaces/cluster-ui/src/store/insights/statementFingerprintInsights/statementFingerprintInsights.reducer.ts b/pkg/ui/workspaces/cluster-ui/src/store/insights/statementFingerprintInsights/statementFingerprintInsights.reducer.ts index e5fa1313283c..7f9ac689fafd 100644 --- a/pkg/ui/workspaces/cluster-ui/src/store/insights/statementFingerprintInsights/statementFingerprintInsights.reducer.ts +++ b/pkg/ui/workspaces/cluster-ui/src/store/insights/statementFingerprintInsights/statementFingerprintInsights.reducer.ts @@ -11,11 +11,11 @@ import { createSlice, PayloadAction } from "@reduxjs/toolkit"; import { DOMAIN_NAME } from "../../utils"; import moment, { Moment } from "moment"; -import { ErrorWithKey, StmtInsightsReq } from "src/api"; +import { ApiResponse, ErrorWithKey, StmtInsightsReq } from "src/api"; import { StmtInsightEvent } from "../../../insights"; export type StatementFingerprintInsightsState = { - data: StmtInsightEvent[] | null; + data: ApiResponse | null; lastUpdated: Moment | null; lastError: Error; valid: boolean; @@ -26,7 +26,7 @@ export type StatementFingerprintInsightsCachedState = { }; export type FingerprintInsightResponseWithKey = { - response: StmtInsightEvent[]; + response: ApiResponse; key: string; }; diff --git a/pkg/ui/workspaces/cluster-ui/src/store/insights/statementFingerprintInsights/statementFingerprintInsights.selectors.ts b/pkg/ui/workspaces/cluster-ui/src/store/insights/statementFingerprintInsights/statementFingerprintInsights.selectors.ts index fece33225470..92476371d527 100644 --- a/pkg/ui/workspaces/cluster-ui/src/store/insights/statementFingerprintInsights/statementFingerprintInsights.selectors.ts +++ b/pkg/ui/workspaces/cluster-ui/src/store/insights/statementFingerprintInsights/statementFingerprintInsights.selectors.ts @@ -20,6 +20,6 @@ export const selectStatementFingerprintInsights = createSelector( if (!cachedFingerprintInsights) { return null; } - return cachedFingerprintInsights[fingerprintID]?.data; + return cachedFingerprintInsights[fingerprintID]?.data?.results; }, ); diff --git a/pkg/ui/workspaces/cluster-ui/src/store/insights/statementInsights/statementInsights.reducer.ts b/pkg/ui/workspaces/cluster-ui/src/store/insights/statementInsights/statementInsights.reducer.ts index 4c53e909a35a..e30ba98747f3 100644 --- a/pkg/ui/workspaces/cluster-ui/src/store/insights/statementInsights/statementInsights.reducer.ts +++ b/pkg/ui/workspaces/cluster-ui/src/store/insights/statementInsights/statementInsights.reducer.ts @@ -11,11 +11,11 @@ import { createSlice, PayloadAction } from "@reduxjs/toolkit"; import { DOMAIN_NAME } from "../../utils"; import { StmtInsightEvent } from "src/insights"; -import { StmtInsightsReq } from "src/api"; +import { ApiResponse, StmtInsightsReq } from "src/api"; import moment from "moment"; export type StmtInsightsState = { - data: StmtInsightEvent[]; + data: ApiResponse; lastError: Error; valid: boolean; inFlight: boolean; @@ -34,7 +34,7 @@ const statementInsightsSlice = createSlice({ name: `${DOMAIN_NAME}/statementInsightsSlice`, initialState, reducers: { - received: (state, action: PayloadAction) => { + received: (state, action: PayloadAction>) => { state.data = action.payload; state.valid = true; state.lastError = null; diff --git a/pkg/ui/workspaces/cluster-ui/src/store/insights/statementInsights/statementInsights.selectors.ts b/pkg/ui/workspaces/cluster-ui/src/store/insights/statementInsights/statementInsights.selectors.ts index 4b46d13f1fee..7f4a3f39e3a2 100644 --- a/pkg/ui/workspaces/cluster-ui/src/store/insights/statementInsights/statementInsights.selectors.ts +++ b/pkg/ui/workspaces/cluster-ui/src/store/insights/statementInsights/statementInsights.selectors.ts @@ -20,11 +20,14 @@ import { selectStatementFingerprintID, selectID } from "src/selectors/common"; import { InsightEnumToLabel, StmtInsightEvent } from "src/insights"; export const selectStmtInsights = (state: AppState): StmtInsightEvent[] => - state.adminUI.stmtInsights?.data; + state.adminUI.stmtInsights?.data?.results; export const selectStmtInsightsError = (state: AppState): Error | null => state.adminUI.stmtInsights?.lastError; +export const selectStmtInsightsMaxApiReached = (state: AppState): boolean => + state.adminUI.stmtInsights?.data?.maxSizeReached; + export const selectStmtInsightDetails = createSelector( selectStmtInsights, selectID, diff --git a/pkg/ui/workspaces/db-console/src/redux/apiReducers.ts b/pkg/ui/workspaces/db-console/src/redux/apiReducers.ts index 091e63cde6d6..42bb79f2aa2b 100644 --- a/pkg/ui/workspaces/db-console/src/redux/apiReducers.ts +++ b/pkg/ui/workspaces/db-console/src/redux/apiReducers.ts @@ -557,11 +557,15 @@ export interface APIReducersState { userSQLRoles: CachedDataReducerState; hotRanges: PaginatedCachedDataReducerState; clusterLocks: CachedDataReducerState; - stmtInsights: CachedDataReducerState; + stmtInsights: CachedDataReducerState< + clusterUiApi.ApiResponse + >; txnInsightDetails: KeyedCachedDataReducerState; txnInsights: CachedDataReducerState; schemaInsights: CachedDataReducerState; - statementFingerprintInsights: KeyedCachedDataReducerState; + statementFingerprintInsights: KeyedCachedDataReducerState< + clusterUiApi.ApiResponse + >; schedules: KeyedCachedDataReducerState; schedule: KeyedCachedDataReducerState; snapshots: KeyedCachedDataReducerState; diff --git a/pkg/ui/workspaces/db-console/src/views/insights/insightsSelectors.ts b/pkg/ui/workspaces/db-console/src/views/insights/insightsSelectors.ts index fa07aa1cccb2..a2004c6bba96 100644 --- a/pkg/ui/workspaces/db-console/src/views/insights/insightsSelectors.ts +++ b/pkg/ui/workspaces/db-console/src/views/insights/insightsSelectors.ts @@ -70,8 +70,19 @@ const selectTxnInsight = createSelector( }, ); -export const selectStmtInsights = (state: AdminUIState) => - state.cachedData.stmtInsights?.data; +export const selectStmtInsights = (state: AdminUIState) => { + return state.cachedData.stmtInsights?.data + ? state.cachedData.stmtInsights.data["results"] + : null; +}; + +export const selectStmtInsightsMaxApiReached = ( + state: AdminUIState, +): boolean => { + return state.cachedData.stmtInsights?.data + ? state.cachedData.stmtInsights?.data["maxSizeReached"] + : false; +}; export const selectTxnInsightDetails = createSelector( selectTxnInsight, diff --git a/pkg/ui/workspaces/db-console/src/views/insights/workloadInsightsPage.tsx b/pkg/ui/workspaces/db-console/src/views/insights/workloadInsightsPage.tsx index 97eae0e9ee00..dadccec16f82 100644 --- a/pkg/ui/workspaces/db-console/src/views/insights/workloadInsightsPage.tsx +++ b/pkg/ui/workspaces/db-console/src/views/insights/workloadInsightsPage.tsx @@ -30,6 +30,7 @@ import { selectStmtInsightsLoading, selectTransactionInsightsLoading, selectInsightTypes, + selectStmtInsightsMaxApiReached, } from "src/views/insights/insightsSelectors"; import { bindActionCreators } from "redux"; import { LocalSetting } from "src/redux/localsettings"; @@ -75,6 +76,7 @@ const statementMapStateToProps = ( insightStatementColumnsLocalSetting.selectorToArray(state), timeScale: selectTimeScale(state), isLoading: selectStmtInsightsLoading(state), + maxSizeApiReached: selectStmtInsightsMaxApiReached(state), }); const TransactionDispatchProps = { diff --git a/pkg/ui/workspaces/db-console/src/views/statements/statementDetails.tsx b/pkg/ui/workspaces/db-console/src/views/statements/statementDetails.tsx index e5fcbcefac14..5268377f8e0d 100644 --- a/pkg/ui/workspaces/db-console/src/views/statements/statementDetails.tsx +++ b/pkg/ui/workspaces/db-console/src/views/statements/statementDetails.tsx @@ -108,7 +108,7 @@ const selectStatementFingerprintInsights = createSelector( (_state: AdminUIState, props: RouteComponentProps): string => getMatchParamByName(props.match, statementAttr), (cachedFingerprintInsights, fingerprintID) => { - return cachedFingerprintInsights[fingerprintID]?.data; + return cachedFingerprintInsights[fingerprintID]?.data?.results; }, );