[WEB-2001] feat: Fix local cache issues r4 (#5726)

* - Handle single quotes in load workspace queries
- Add IS null where condition in query utils

* Fix description_html being lost

* Change secondary order to sequence_id

* Fix update persistence layer

* Add instrumentation

* - Fallback to server incase of any error
This commit is contained in:
Satish Gandham 2024-10-01 14:18:01 +05:30 committed by GitHub
parent 927d265209
commit 33f6c1fe9e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 59 additions and 9 deletions

View file

@ -1,3 +1,4 @@
import * as Sentry from "@sentry/nextjs";
import set from "lodash/set";
// plane
import { EIssueGroupBYServerToProperty } from "@plane/constants";
@ -15,7 +16,7 @@ import { loadWorkSpaceData } from "./utils/load-workspace";
import { issueFilterCountQueryConstructor, issueFilterQueryConstructor } from "./utils/query-constructor";
import { runQuery } from "./utils/query-executor";
import { createTables } from "./utils/tables";
import { logError, getGroupedIssueResults, getSubGroupedIssueResults, logInfo, log } from "./utils/utils";
import { getGroupedIssueResults, getSubGroupedIssueResults, log, logError, logInfo } from "./utils/utils";
declare module "@sqlite.org/sqlite-wasm" {
export function sqlite3Worker1Promiser(...args: any): any;
@ -67,7 +68,7 @@ export class Storage {
this.reset();
}
try {
await this._initialize(workspaceSlug);
await Sentry.startSpan({ name: "INIT_DB" }, async () => await this._initialize(workspaceSlug));
return true;
} catch (err) {
logError(err);
@ -148,7 +149,9 @@ export class Storage {
syncWorkspace = async () => {
if (document.hidden || !rootStore.user.localDBEnabled) return; // return if the window gets hidden
loadWorkSpaceData(this.workspaceSlug);
await Sentry.startSpan({ name: "LOAD_WS", attributes: { slug: this.workspaceSlug } }, async () => {
await loadWorkSpaceData(this.workspaceSlug);
});
};
syncProject = async (projectId: string) => {
@ -173,7 +176,7 @@ export class Storage {
if (document.hidden || !rootStore.user.localDBEnabled) return false; // return if the window gets hidden
try {
const sync = this._syncIssues(projectId);
const sync = Sentry.startSpan({ name: `SYNC_ISSUES` }, () => this._syncIssues(projectId));
this.setSync(projectId, sync);
await sync;
} catch (e) {
@ -183,6 +186,8 @@ export class Storage {
};
_syncIssues = async (projectId: string) => {
const activeSpan = Sentry.getActiveSpan();
log("### Sync started");
let status = this.getStatus(projectId);
if (status === "loading" || status === "syncing") {
@ -242,6 +247,11 @@ export class Storage {
this.setOption(projectId, "ready");
this.setStatus(projectId, "ready");
this.setSync(projectId, undefined);
activeSpan?.setAttributes({
projectId: projectId,
count: response.total_count,
});
};
getIssueCount = async (projectId: string) => {
@ -279,7 +289,9 @@ export class Storage {
currentProjectStatus === "error" ||
!rootStore.user.localDBEnabled
) {
logInfo(`Project ${projectId} is loading, falling back to server`);
if (rootStore.user.localDBEnabled) {
logInfo(`Project ${projectId} is loading, falling back to server`);
}
const issueService = new IssueService();
return await issueService.getIssuesFromServer(workspaceSlug, projectId, queries);
}
@ -289,7 +301,15 @@ export class Storage {
const query = issueFilterQueryConstructor(this.workspaceSlug, projectId, queries);
const countQuery = issueFilterCountQueryConstructor(this.workspaceSlug, projectId, queries);
const start = performance.now();
const [issuesRaw, count] = await Promise.all([runQuery(query), runQuery(countQuery)]);
let issuesRaw: any[] = [];
let count: any[];
try {
[issuesRaw, count] = await Promise.all([runQuery(query), runQuery(countQuery)]);
} catch (e) {
logError(e);
const issueService = new IssueService();
return await issueService.getIssuesFromServer(workspaceSlug, projectId, queries);
}
// const issuesRaw = await runQuery(query);
const end = performance.now();
@ -318,6 +338,8 @@ export class Storage {
issueResults = getGroupedIssueResults(issueResults);
}
}
const groupCount = group_by ? Object.keys(issueResults).length : undefined;
const subGroupCount = sub_group_by ? Object.keys(issueResults[Object.keys(issueResults)[0]]).length : undefined;
const groupingEnd = performance.now();
const times = {
@ -341,6 +363,17 @@ export class Storage {
total_pages,
};
const activeSpan = Sentry.getActiveSpan();
activeSpan?.setAttributes({
projectId,
count: total_count,
groupBy: group_by,
subGroupBy: sub_group_by,
queries: queries,
local: true,
groupCount,
subGroupCount,
});
return out;
};
@ -353,6 +386,7 @@ export class Storage {
return formatLocalIssue(issues[0]);
}
} catch (err) {
logError(err);
console.warn("unable to fetch issue from local db");
}

View file

@ -330,7 +330,7 @@ const getSingleFilterFields = (queries: any) => {
export const getIssueFieldsFragment = () => {
const { description_html, ...filtered } = issueSchema;
const keys = Object.keys(filtered);
const sql = ` ${keys.map((key, index) => `i.${key}`).join(`,
const sql = ` ${keys.map((key) => `i.${key}`).join(`,
`)}`;
return sql;
};

View file

@ -1,3 +1,4 @@
import * as Sentry from "@sentry/nextjs";
import pick from "lodash/pick";
import { TIssue } from "@plane/types";
import { rootStore } from "@/lib/store-context";
@ -9,7 +10,13 @@ export const log = (...args: any) => {
console.log(...args);
}
};
export const logError = console.error;
export const logError = (e: any) => {
if (e?.result?.errorClass === "SQLite3Error") {
e = parseSQLite3Error(e);
}
Sentry.captureException(e);
console.log(e);
};
export const logInfo = console.info;
export const updatePersistentLayer = async (issueIds: string | string[]) => {
@ -140,3 +147,8 @@ export const getSubGroupedIssueResults = (
};
export const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
const parseSQLite3Error = (error: any) => {
error.result = JSON.stringify(error.result);
return error;
};

View file

@ -1,3 +1,4 @@
import * as Sentry from "@sentry/nextjs";
// types
import type {
IIssueDisplayProperties,
@ -69,7 +70,10 @@ export class IssueService extends APIService {
}
async getIssues(workspaceSlug: string, projectId: string, queries?: any, config = {}): Promise<TIssuesResponse> {
const response = await persistence.getIssues(workspaceSlug, projectId, queries, config);
const response = await Sentry.startSpan({ name: "GET_ISSUES" }, async () => {
const res = await persistence.getIssues(workspaceSlug, projectId, queries, config);
return res;
});
return response as TIssuesResponse;
}