[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:
parent
927d265209
commit
33f6c1fe9e
4 changed files with 59 additions and 9 deletions
|
|
@ -1,3 +1,4 @@
|
||||||
|
import * as Sentry from "@sentry/nextjs";
|
||||||
import set from "lodash/set";
|
import set from "lodash/set";
|
||||||
// plane
|
// plane
|
||||||
import { EIssueGroupBYServerToProperty } from "@plane/constants";
|
import { EIssueGroupBYServerToProperty } from "@plane/constants";
|
||||||
|
|
@ -15,7 +16,7 @@ import { loadWorkSpaceData } from "./utils/load-workspace";
|
||||||
import { issueFilterCountQueryConstructor, issueFilterQueryConstructor } from "./utils/query-constructor";
|
import { issueFilterCountQueryConstructor, issueFilterQueryConstructor } from "./utils/query-constructor";
|
||||||
import { runQuery } from "./utils/query-executor";
|
import { runQuery } from "./utils/query-executor";
|
||||||
import { createTables } from "./utils/tables";
|
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" {
|
declare module "@sqlite.org/sqlite-wasm" {
|
||||||
export function sqlite3Worker1Promiser(...args: any): any;
|
export function sqlite3Worker1Promiser(...args: any): any;
|
||||||
|
|
@ -67,7 +68,7 @@ export class Storage {
|
||||||
this.reset();
|
this.reset();
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
await this._initialize(workspaceSlug);
|
await Sentry.startSpan({ name: "INIT_DB" }, async () => await this._initialize(workspaceSlug));
|
||||||
return true;
|
return true;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logError(err);
|
logError(err);
|
||||||
|
|
@ -148,7 +149,9 @@ export class Storage {
|
||||||
|
|
||||||
syncWorkspace = async () => {
|
syncWorkspace = async () => {
|
||||||
if (document.hidden || !rootStore.user.localDBEnabled) return; // return if the window gets hidden
|
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) => {
|
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
|
if (document.hidden || !rootStore.user.localDBEnabled) return false; // return if the window gets hidden
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const sync = this._syncIssues(projectId);
|
const sync = Sentry.startSpan({ name: `SYNC_ISSUES` }, () => this._syncIssues(projectId));
|
||||||
this.setSync(projectId, sync);
|
this.setSync(projectId, sync);
|
||||||
await sync;
|
await sync;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
@ -183,6 +186,8 @@ export class Storage {
|
||||||
};
|
};
|
||||||
|
|
||||||
_syncIssues = async (projectId: string) => {
|
_syncIssues = async (projectId: string) => {
|
||||||
|
const activeSpan = Sentry.getActiveSpan();
|
||||||
|
|
||||||
log("### Sync started");
|
log("### Sync started");
|
||||||
let status = this.getStatus(projectId);
|
let status = this.getStatus(projectId);
|
||||||
if (status === "loading" || status === "syncing") {
|
if (status === "loading" || status === "syncing") {
|
||||||
|
|
@ -242,6 +247,11 @@ export class Storage {
|
||||||
this.setOption(projectId, "ready");
|
this.setOption(projectId, "ready");
|
||||||
this.setStatus(projectId, "ready");
|
this.setStatus(projectId, "ready");
|
||||||
this.setSync(projectId, undefined);
|
this.setSync(projectId, undefined);
|
||||||
|
|
||||||
|
activeSpan?.setAttributes({
|
||||||
|
projectId: projectId,
|
||||||
|
count: response.total_count,
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
getIssueCount = async (projectId: string) => {
|
getIssueCount = async (projectId: string) => {
|
||||||
|
|
@ -279,7 +289,9 @@ export class Storage {
|
||||||
currentProjectStatus === "error" ||
|
currentProjectStatus === "error" ||
|
||||||
!rootStore.user.localDBEnabled
|
!rootStore.user.localDBEnabled
|
||||||
) {
|
) {
|
||||||
|
if (rootStore.user.localDBEnabled) {
|
||||||
logInfo(`Project ${projectId} is loading, falling back to server`);
|
logInfo(`Project ${projectId} is loading, falling back to server`);
|
||||||
|
}
|
||||||
const issueService = new IssueService();
|
const issueService = new IssueService();
|
||||||
return await issueService.getIssuesFromServer(workspaceSlug, projectId, queries);
|
return await issueService.getIssuesFromServer(workspaceSlug, projectId, queries);
|
||||||
}
|
}
|
||||||
|
|
@ -289,7 +301,15 @@ export class Storage {
|
||||||
const query = issueFilterQueryConstructor(this.workspaceSlug, projectId, queries);
|
const query = issueFilterQueryConstructor(this.workspaceSlug, projectId, queries);
|
||||||
const countQuery = issueFilterCountQueryConstructor(this.workspaceSlug, projectId, queries);
|
const countQuery = issueFilterCountQueryConstructor(this.workspaceSlug, projectId, queries);
|
||||||
const start = performance.now();
|
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 issuesRaw = await runQuery(query);
|
||||||
const end = performance.now();
|
const end = performance.now();
|
||||||
|
|
||||||
|
|
@ -318,6 +338,8 @@ export class Storage {
|
||||||
issueResults = getGroupedIssueResults(issueResults);
|
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 groupingEnd = performance.now();
|
||||||
|
|
||||||
const times = {
|
const times = {
|
||||||
|
|
@ -341,6 +363,17 @@ export class Storage {
|
||||||
total_pages,
|
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;
|
return out;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -353,6 +386,7 @@ export class Storage {
|
||||||
return formatLocalIssue(issues[0]);
|
return formatLocalIssue(issues[0]);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
logError(err);
|
||||||
console.warn("unable to fetch issue from local db");
|
console.warn("unable to fetch issue from local db");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -330,7 +330,7 @@ const getSingleFilterFields = (queries: any) => {
|
||||||
export const getIssueFieldsFragment = () => {
|
export const getIssueFieldsFragment = () => {
|
||||||
const { description_html, ...filtered } = issueSchema;
|
const { description_html, ...filtered } = issueSchema;
|
||||||
const keys = Object.keys(filtered);
|
const keys = Object.keys(filtered);
|
||||||
const sql = ` ${keys.map((key, index) => `i.${key}`).join(`,
|
const sql = ` ${keys.map((key) => `i.${key}`).join(`,
|
||||||
`)}`;
|
`)}`;
|
||||||
return sql;
|
return sql;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import * as Sentry from "@sentry/nextjs";
|
||||||
import pick from "lodash/pick";
|
import pick from "lodash/pick";
|
||||||
import { TIssue } from "@plane/types";
|
import { TIssue } from "@plane/types";
|
||||||
import { rootStore } from "@/lib/store-context";
|
import { rootStore } from "@/lib/store-context";
|
||||||
|
|
@ -9,7 +10,13 @@ export const log = (...args: any) => {
|
||||||
console.log(...args);
|
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 logInfo = console.info;
|
||||||
|
|
||||||
export const updatePersistentLayer = async (issueIds: string | string[]) => {
|
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));
|
export const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
|
||||||
|
|
||||||
|
const parseSQLite3Error = (error: any) => {
|
||||||
|
error.result = JSON.stringify(error.result);
|
||||||
|
return error;
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import * as Sentry from "@sentry/nextjs";
|
||||||
// types
|
// types
|
||||||
import type {
|
import type {
|
||||||
IIssueDisplayProperties,
|
IIssueDisplayProperties,
|
||||||
|
|
@ -69,7 +70,10 @@ export class IssueService extends APIService {
|
||||||
}
|
}
|
||||||
|
|
||||||
async getIssues(workspaceSlug: string, projectId: string, queries?: any, config = {}): Promise<TIssuesResponse> {
|
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;
|
return response as TIssuesResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue