Skip to content
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
d7288b8
chore: cache allKeys and dependencyMap computation on client
Aug 29, 2024
502aeaa
Add fn to check if the computation is cached
Aug 29, 2024
c2db605
Move exported types to a seperate file
Aug 29, 2024
795e3fc
Change evalTree to async fn
Aug 30, 2024
8c16bfb
Merge remote-tracking branch 'origin' into chore/cache-eval-computati…
Aug 30, 2024
0c89ada
Merge remote-tracking branch 'origin' into chore/cache-eval-computati…
Aug 30, 2024
e6fd4a2
Merge remote-tracking branch 'origin' into chore/cache-eval-computati…
Sep 9, 2024
0e9b52d
Change evalTree and setupFirstTree to async fns
Sep 9, 2024
d7ff9e3
Add caching for allkeys and dep map calculations
Sep 9, 2024
5a2244c
Revert allKeys caching
Sep 9, 2024
d4a61f9
chore: remove published page fetch in view mode and reuse the consoli…
Sep 10, 2024
dce5339
Add comments
Sep 10, 2024
9ff7947
Revert changes
Sep 10, 2024
a2710a0
Patch fix for double dispatch of FETCH_ALL_PAGE_ENTITY_COMPLETION
Sep 10, 2024
6e24abf
Check for undefined timestamp
Sep 10, 2024
2119599
type refactor
Sep 10, 2024
2a426f0
Merge remote-tracking branch 'origin' into chore/cache-eval-computati…
Sep 11, 2024
cc3e898
arguments refactor
Sep 11, 2024
853beb3
Add timestamp to cache key and delete invalid cache entries for old t…
Sep 11, 2024
51d54c2
Profile add nodes and addDependency methods in createDepMap fn
Sep 11, 2024
a9c693c
Add test cases
Sep 11, 2024
21327a0
Fix test cases for EvaluationSaga
Sep 11, 2024
11de620
Fix test cases
Sep 11, 2024
5c8803e
Merge remote-tracking branch 'origin' into chore/cache-eval-computati…
Sep 14, 2024
54bdb16
await setupFirstTree in beforeEach
Sep 14, 2024
c72291c
Add dynamic timestamp for setupFirstTree in DataTreeEvaluator test cases
Sep 14, 2024
85535c4
Update test cases
Sep 16, 2024
726c80e
fix: remove redundant eval trigger
Sep 19, 2024
0a18cfe
fix type in jest test
Sep 19, 2024
74b96f6
Add a comment and change the debounce timer to 5 seconds
Sep 20, 2024
002a021
Merge remote-tracking branch 'origin' into chore/cache-eval-computati…
Sep 20, 2024
59286e6
Merge remote-tracking branch 'origin' into chore/cache-eval-computati…
Sep 20, 2024
2df05ed
revert patch fix
Sep 20, 2024
24be553
Merge branch 'fix/redundant-eval-trigger-ce', remote-tracking branch …
Sep 20, 2024
d84db3f
Merge remote-tracking branch 'origin' into chore/cache-eval-computati…
Oct 14, 2024
744bff1
Fix lint issues
Oct 14, 2024
dfcadfe
Remove workspace id from cache props
Oct 15, 2024
a42791b
fix test cases after prev change
Oct 15, 2024
af545a2
fix test cases after prev change
Oct 15, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion app/client/src/UITelemetry/generateWebWorkerTraces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export interface WebworkerSpanData {
//to regular otlp telemetry data and subsequently exported to our telemetry collector
export const newWebWorkerSpanData = (
spanName: string,
attributes: SpanAttributes,
attributes: SpanAttributes = {},
): WebworkerSpanData => {
return {
attributes,
Expand All @@ -28,6 +28,19 @@ const addEndTimeForWebWorkerSpanData = (span: WebworkerSpanData) => {
span.endTime = Date.now();
};

export const profileAsyncFn = async <T>(
spanName: string,
fn: () => Promise<T>,
allSpans: Record<string, WebworkerSpanData | SpanAttributes>,
attributes: SpanAttributes = {},
) => {
const span = newWebWorkerSpanData(spanName, attributes);
const res: T = await fn();
addEndTimeForWebWorkerSpanData(span);
allSpans[spanName] = span;
return res;
};

export const profileFn = <T>(
spanName: string,
attributes: SpanAttributes = {},
Expand Down
7 changes: 3 additions & 4 deletions app/client/src/ce/sagas/PageSagas.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -402,11 +402,10 @@ export function* fetchPublishedPageResourcesSaga(
// We need to recall consolidated view API in order to fetch actions when page is switched
// As in the first call only actions of the current page are fetched
// In future, we can reuse this saga to fetch other resources of the page like actionCollections etc
const { publishedActions } = response;
const { pages, publishedActions } = response;

// Sending applicationId as empty as we have publishedActions present,
// it won't call the actions view api with applicationId
yield put(fetchActionsForView({ applicationId: "", publishedActions }));
const applicationId = pages.data.application.id;
yield put(fetchActionsForView({ applicationId, publishedActions }));
yield put(fetchAllPageEntityCompletion([executePageLoadActions()]));
}
} catch (error) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
export enum EVAL_WORKER_SYNC_ACTION {
SETUP = "SETUP",
EVAL_TREE = "EVAL_TREE",
EVAL_ACTION_BINDINGS = "EVAL_ACTION_BINDINGS",
CLEAR_CACHE = "CLEAR_CACHE",
VALIDATE_PROPERTY = "VALIDATE_PROPERTY",
Expand All @@ -16,6 +15,7 @@ export enum EVAL_WORKER_SYNC_ACTION {
}

export enum EVAL_WORKER_ASYNC_ACTION {
EVAL_TREE = "EVAL_TREE",
EVAL_TRIGGER = "EVAL_TRIGGER",
EVAL_EXPRESSION = "EVAL_EXPRESSION",
LOAD_LIBRARIES = "LOAD_LIBRARIES",
Expand Down
7 changes: 5 additions & 2 deletions app/client/src/pages/AppViewer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import { CANVAS_SELECTOR } from "constants/WidgetConstants";
import {
setupPublishedPage,
fetchPublishedPageResourcesAction,
updateCurrentPage,
} from "actions/pageActions";
import usePrevious from "utils/hooks/usePrevious";
import { getIsBranchUpdated } from "../utils";
Expand Down Expand Up @@ -163,8 +164,10 @@ function AppViewer(props: Props) {
(page) => page.basePageId === basePageId,
)?.pageId;
if (pageId) {
dispatch(setupPublishedPage(pageId, true));

dispatch(updateCurrentPage(pageId));
// TODO: Patch fix to avoid dispatch of FETCH_ALL_PAGE_ENTITY_COMPLETION twice
// Remove this once Sneha's PR is merged
dispatch(setupPublishedPage(pageId, true, true));
// Used for fetching page resources
dispatch(fetchPublishedPageResourcesAction(basePageId));
}
Expand Down
56 changes: 56 additions & 0 deletions app/client/src/sagas/EvaluationsSaga.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,14 @@ import {
} from "ee/constants/ReduxActionConstants";
import { fetchPluginFormConfigsSuccess } from "actions/pluginActions";
import { createJSCollectionSuccess } from "actions/jsActionActions";
import { getInstanceId } from "ee/selectors/tenantSelectors";
import {
getApplicationLastDeployedAt,
getCurrentApplicationId,
getCurrentPageId,
} from "selectors/editorSelectors";
import { getCurrentWorkspaceId } from "ee/selectors/selectedWorkspaceSelectors";

jest.mock("loglevel");

describe("evaluateTreeSaga", () => {
Expand All @@ -39,8 +47,24 @@ describe("evaluateTreeSaga", () => {
[select(getSelectedAppTheme), {}],
[select(getAppMode), false],
[select(getWidgetsMeta), {}],
[select(getInstanceId), "instanceId"],
[select(getCurrentWorkspaceId), "workspaceId"],
[select(getCurrentApplicationId), "applicationId"],
[select(getCurrentPageId), "pageId"],
[
select(getApplicationLastDeployedAt),
new Date("11 September 2024").toISOString(),
],
])
.call(evalWorker.request, EVAL_WORKER_ACTIONS.EVAL_TREE, {
cacheProps: {
instanceId: "instanceId",
workspaceId: "workspaceId",
appId: "applicationId",
pageId: "pageId",
appMode: false,
timestamp: new Date("11 September 2024").toISOString(),
},
unevalTree: unEvalAndConfigTree,
widgetTypeConfigMap: undefined,
widgets: {},
Expand Down Expand Up @@ -69,8 +93,24 @@ describe("evaluateTreeSaga", () => {
[select(getSelectedAppTheme), {}],
[select(getAppMode), false],
[select(getWidgetsMeta), {}],
[select(getInstanceId), "instanceId"],
[select(getCurrentApplicationId), "applicationId"],
[select(getCurrentPageId), "pageId"],
[
select(getApplicationLastDeployedAt),
new Date("11 September 2024").toISOString(),
],
[select(getCurrentWorkspaceId), "workspaceId"],
])
.call(evalWorker.request, EVAL_WORKER_ACTIONS.EVAL_TREE, {
cacheProps: {
instanceId: "instanceId",
workspaceId: "workspaceId",
appId: "applicationId",
pageId: "pageId",
appMode: false,
timestamp: new Date("11 September 2024").toISOString(),
},
unevalTree: unEvalAndConfigTree,
widgetTypeConfigMap: undefined,
widgets: {},
Expand Down Expand Up @@ -109,8 +149,24 @@ describe("evaluateTreeSaga", () => {
[select(getSelectedAppTheme), {}],
[select(getAppMode), false],
[select(getWidgetsMeta), {}],
[select(getInstanceId), "instanceId"],
[select(getCurrentApplicationId), "applicationId"],
[select(getCurrentPageId), "pageId"],
[
select(getApplicationLastDeployedAt),
new Date("11 September 2024").toISOString(),
],
[select(getCurrentWorkspaceId), "workspaceId"],
])
.call(evalWorker.request, EVAL_WORKER_ACTIONS.EVAL_TREE, {
cacheProps: {
instanceId: "instanceId",
workspaceId: "workspaceId",
appId: "applicationId",
pageId: "pageId",
appMode: false,
timestamp: new Date("11 September 2024").toISOString(),
},
unevalTree: unEvalAndConfigTree,
widgetTypeConfigMap: undefined,
widgets: {},
Expand Down
21 changes: 20 additions & 1 deletion app/client/src/sagas/EvaluationsSaga.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,13 @@ import { evalErrorHandler } from "./EvalErrorHandler";
import AnalyticsUtil from "ee/utils/AnalyticsUtil";
import { endSpan, startRootSpan } from "UITelemetry/generateTraces";
import { transformTriggerEvalErrors } from "ee/sagas/helpers";
import {
getApplicationLastDeployedAt,
getCurrentApplicationId,
getCurrentPageId,
} from "selectors/editorSelectors";
import { getInstanceId } from "ee/selectors/tenantSelectors";
import { getCurrentWorkspaceId } from "ee/selectors/selectedWorkspaceSelectors";

const APPSMITH_CONFIGS = getAppsmithConfigs();
export const evalWorker = new GracefulWorkerService(
Expand Down Expand Up @@ -253,14 +260,26 @@ export function* evaluateTreeSaga(
const theme: ReturnType<typeof getSelectedAppTheme> =
yield select(getSelectedAppTheme);
log.debug({ unevalTree, configTree: unEvalAndConfigTree.configTree });

const instanceId: string = yield select(getInstanceId);
const workspaceId: string = yield select(getCurrentWorkspaceId);
const applicationId: string = yield select(getCurrentApplicationId);
const pageId: string = yield select(getCurrentPageId);
const lastDeployedAt: string = yield select(getApplicationLastDeployedAt);
const appMode: ReturnType<typeof getAppMode> = yield select(getAppMode);
const widgetsMeta: ReturnType<typeof getWidgetsMeta> =
yield select(getWidgetsMeta);

const shouldRespondWithLogs = log.getLevel() === log.levels.DEBUG;

const evalTreeRequestData: EvalTreeRequestData = {
cacheProps: {
appMode,
appId: applicationId,
pageId,
timestamp: lastDeployedAt,
instanceId,
workspaceId,
},
unevalTree: unEvalAndConfigTree,
widgetTypeConfigMap,
widgets,
Expand Down
17 changes: 15 additions & 2 deletions app/client/src/workers/Evaluation/__tests__/evaluation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import WidgetFactory from "WidgetProvider/factory";
import { generateDataTreeWidget } from "entities/DataTree/dataTreeWidget";
import { sortObjectWithArray } from "../../../utils/treeUtils";
import klona from "klona";
import { APP_MODE } from "entities/App";

const klonaFullSpy = jest.fn();
jest.mock("klona/full", () => ({
Expand Down Expand Up @@ -563,8 +564,20 @@ describe("DataTreeEvaluator", () => {

const evaluator = new DataTreeEvaluator(WIDGET_CONFIG_MAP);

it("Checks the number of clone operations in first tree flow", () => {
evaluator.setupFirstTree(unEvalTree, configTree);
it("Checks the number of clone operations in first tree flow", async () => {
await evaluator.setupFirstTree(
unEvalTree,
configTree,
{},
{
appId: "appId",
pageId: "pageId",
timestamp: "timestamp",
appMode: APP_MODE.PUBLISHED,
instanceId: "instanceId",
workspaceId: "workspaceId",
},
);
evaluator.evalAndValidateFirstTree();
// Hard check to not regress on the number of clone operations. Try to improve this number.
expect(klonaFullSpy).toBeCalledTimes(41);
Expand Down
17 changes: 15 additions & 2 deletions app/client/src/workers/Evaluation/evalTreeWithChanges.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import type { WidgetEntity } from "plugins/Linting/lib/entity/WidgetEntity";
import type { UpdateDataTreeMessageData } from "sagas/EvalWorkerActionSagas";
import DataTreeEvaluator from "workers/common/DataTreeEvaluator";
import * as evalTreeWithChanges from "./evalTreeWithChanges";
import { APP_MODE } from "entities/App";
export const BASE_WIDGET = {
widgetId: "randomID",
widgetName: "randomWidgetName",
Expand Down Expand Up @@ -179,9 +180,21 @@ describe("evaluateAndGenerateResponse", () => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return updates.filter((p: any) => !p.rhs.__evaluation__);
};
beforeEach(() => {
beforeEach(async () => {
evaluator = new DataTreeEvaluator(WIDGET_CONFIG_MAP);
evaluator.setupFirstTree(unEvalTree, configTree);
await evaluator.setupFirstTree(
unEvalTree,
configTree,
{},
{
appId: "appId",
pageId: "pageId",
timestamp: "timestamp",
appMode: APP_MODE.PUBLISHED,
instanceId: "instanceId",
workspaceId: "workspaceId",
},
);
evaluator.evalAndValidateFirstTree();
});

Expand Down
52 changes: 27 additions & 25 deletions app/client/src/workers/Evaluation/handlers/evalTree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,7 @@ import {
CrashingError,
getSafeToRenderDataTree,
} from "ee/workers/Evaluation/evaluationUtils";
import type {
EvalTreeRequestData,
EvalTreeResponseData,
EvalWorkerSyncRequest,
} from "../types";
import type { EvalTreeRequestData, EvalWorkerASyncRequest } from "../types";
import { clearAllIntervals } from "../fns/overrides/interval";
import JSObjectCollection from "workers/Evaluation/JSObject/Collection";
import { getJSVariableCreatedEvents } from "../JSObject/JSVariableEvents";
Expand All @@ -33,6 +29,7 @@ import { MessageType, sendMessage } from "utils/MessageUtil";
import {
profileFn,
newWebWorkerSpanData,
profileAsyncFn,
} from "UITelemetry/generateWebWorkerTraces";
import type { SpanAttributes } from "UITelemetry/generateTraces";
import type { CanvasWidgetsReduxState } from "reducers/entityReducers/canvasWidgetsReducer";
Expand All @@ -49,9 +46,9 @@ export let canvasWidgetsMeta: Record<string, any>;
export let metaWidgetsCache: MetaWidgetsReduxState;
export let canvasWidgets: CanvasWidgetsReduxState;

export function evalTree(
request: EvalWorkerSyncRequest<EvalTreeRequestData>,
): EvalTreeResponseData {
export async function evalTree(
request: EvalWorkerASyncRequest<EvalTreeRequestData>,
) {
const { data, webworkerTelemetry } = request;

webworkerTelemetry["transferDataToWorkerThread"].endTime = Date.now();
Expand All @@ -76,6 +73,7 @@ export function evalTree(
affectedJSObjects,
allActionValidationConfig,
appMode,
cacheProps,
forceEvaluation,
metaWidgets,
shouldReplay,
Expand Down Expand Up @@ -108,16 +106,17 @@ export function evalTree(
allActionValidationConfig,
);

const setupFirstTreeResponse = profileFn(
const setupFirstTreeResponse = await profileAsyncFn(
"setupFirstTree",
{ description: "during initialisation" },
(dataTreeEvaluator as DataTreeEvaluator).setupFirstTree.bind(
dataTreeEvaluator,
unevalTree,
configTree,
webworkerTelemetry,
cacheProps,
),
webworkerTelemetry,
() =>
(dataTreeEvaluator as DataTreeEvaluator).setupFirstTree(
unevalTree,
configTree,
webworkerTelemetry,
),
{ description: "during initialisation" },
);

evalOrder = setupFirstTreeResponse.evalOrder;
Expand All @@ -127,8 +126,9 @@ export function evalTree(
"evalAndValidateFirstTree",
{ description: "during initialisation" },
webworkerTelemetry,
() =>
(dataTreeEvaluator as DataTreeEvaluator).evalAndValidateFirstTree(),
(dataTreeEvaluator as DataTreeEvaluator).evalAndValidateFirstTree.bind(
dataTreeEvaluator,
),
);

dataTree = makeEntityConfigsAsObjProperties(dataTreeResponse.evalTree, {
Expand Down Expand Up @@ -156,15 +156,17 @@ export function evalTree(
);
}

const setupFirstTreeResponse = profileFn(
const setupFirstTreeResponse = await profileAsyncFn(
"setupFirstTree",
{ description: "non-initialisation" },
(dataTreeEvaluator as DataTreeEvaluator).setupFirstTree.bind(
dataTreeEvaluator,
unevalTree,
configTree,
webworkerTelemetry,
cacheProps,
),
webworkerTelemetry,
() =>
(dataTreeEvaluator as DataTreeEvaluator).setupFirstTree(
unevalTree,
configTree,
),
{ description: "non-initialisation" },
);
isCreateFirstTree = true;
evalOrder = setupFirstTreeResponse.evalOrder;
Expand Down
2 changes: 1 addition & 1 deletion app/client/src/workers/Evaluation/handlers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ const syncHandlerMap: Record<
(req: EvalWorkerSyncRequest) => any
> = {
[EVAL_WORKER_ACTIONS.EVAL_ACTION_BINDINGS]: evalActionBindings,
[EVAL_WORKER_ACTIONS.EVAL_TREE]: evalTree,
[EVAL_WORKER_ACTIONS.EVAL_TREE_WITH_CHANGES]: evalTreeWithChanges,
[EVAL_WORKER_ACTIONS.UNDO]: undo,
[EVAL_WORKER_ACTIONS.REDO]: redo,
Expand All @@ -52,6 +51,7 @@ const asyncHandlerMap: Record<
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(req: EvalWorkerASyncRequest) => any
> = {
[EVAL_WORKER_ACTIONS.EVAL_TREE]: evalTree,
[EVAL_WORKER_ACTIONS.EVAL_TRIGGER]: evalTrigger,
[EVAL_WORKER_ACTIONS.EVAL_EXPRESSION]: evalExpression,
[EVAL_WORKER_ACTIONS.LOAD_LIBRARIES]: loadLibraries,
Expand Down
Loading