Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Reduce RTS calls in the updateLayout flow #37127

Merged
merged 47 commits into from
Nov 29, 2024
Merged
Show file tree
Hide file tree
Changes from 38 commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
0c4b37b
Revert "chore: removed unwanted metrics (#37052)"
rishabhrathod01 Oct 29, 2024
a150314
chore: Add metrics to analyse RTS logs
rishabhrathod01 Oct 29, 2024
448f663
Send all bindings together to avoid multiple RTS calls
rishabhrathod01 Oct 29, 2024
e3ec3c0
remove commented code
rishabhrathod01 Oct 31, 2024
65b5492
undo change to verify ci failure cause
rishabhrathod01 Oct 31, 2024
87ffad7
undo change to verify ci failure cause
rishabhrathod01 Nov 1, 2024
28a92e1
fix cypress test
rishabhrathod01 Nov 1, 2024
42a274d
use constants for span
rishabhrathod01 Nov 1, 2024
cfa0d94
undo changes in method to be skipped
rishabhrathod01 Nov 8, 2024
41209f5
undo addDirectly.. method change
rishabhrathod01 Nov 11, 2024
9b3b5f4
send allBindings to getPossibleEntityReferences
rishabhrathod01 Nov 12, 2024
fa2ed2c
remove unused code
rishabhrathod01 Nov 12, 2024
e9fe711
Merge branch 'release' into chore/rts-metrics
Nov 12, 2024
e108c96
trigger CI
rishabhrathod01 Nov 12, 2024
2b0981b
Merge branch 'release' into chore/rts-metrics
rishabhrathod01 Nov 12, 2024
2a8d811
avoid similar binding leading to issues
rishabhrathod01 Nov 18, 2024
55120d3
add unit test
rishabhrathod01 Nov 18, 2024
bae1fec
Merge branch 'release' into chore/rts-metrics
rishabhrathod01 Nov 19, 2024
8e69ab5
fix unit test
rishabhrathod01 Nov 19, 2024
b55d0a8
Merge branch 'release' into chore/rts-metrics
rishabhrathod01 Nov 19, 2024
b732496
add log to debug on ci
rishabhrathod01 Nov 19, 2024
6a42adc
print log to debug unit test
rishabhrathod01 Nov 19, 2024
edb933f
print log to debug unit test
rishabhrathod01 Nov 20, 2024
45000b1
fix unit test
rishabhrathod01 Nov 21, 2024
55c9586
disable migrateDSL when fetching dsl in unit test
rishabhrathod01 Nov 21, 2024
790caa6
resolve comments
rishabhrathod01 Nov 21, 2024
afc92f3
extract common code to reduce code duplicacy
rishabhrathod01 Nov 21, 2024
72a4022
refactor and add comment
rishabhrathod01 Nov 21, 2024
b532bc6
Merge branch 'release' into chore/rts-metrics
rishabhrathod01 Nov 21, 2024
4da0054
Merge branch 'release' into chore/rts-metrics
rishabhrathod01 Nov 21, 2024
4206960
remove unrequired constructor
rishabhrathod01 Nov 22, 2024
29eb2d0
undo common code separation
rishabhrathod01 Nov 24, 2024
e0a2bda
undo changes
rishabhrathod01 Nov 25, 2024
22c00cb
spotless apply
rishabhrathod01 Nov 25, 2024
ae70aa5
fix method type
rishabhrathod01 Nov 25, 2024
fc5ef6a
Merge branch 'release' into chore/rts-metrics
rishabhrathod01 Nov 25, 2024
bdd2e7f
simplify logic to be more readable
rishabhrathod01 Nov 26, 2024
98b7eb5
mock unit test for allBindings
rishabhrathod01 Nov 26, 2024
5e4ffe1
Merge branch 'release' into chore/rts-metrics
rishabhrathod01 Nov 26, 2024
191e96f
return edgesRef like before
rishabhrathod01 Nov 27, 2024
a6d2b46
Merge branch 'release' into chore/rts-metrics
rishabhrathod01 Nov 27, 2024
d1b3791
Revert "simplify logic to be more readable"
rishabhrathod01 Nov 27, 2024
75210b1
Merge branch 'release' into chore/rts-metrics
rishabhrathod01 Nov 27, 2024
01e13b7
Merge branch 'release' into chore/rts-metrics
rishabhrathod01 Nov 28, 2024
da8b8d6
remove unused span
rishabhrathod01 Nov 28, 2024
f58d22b
retain comment
rishabhrathod01 Nov 28, 2024
07b68d4
Merge branch 'release' into chore/rts-metrics
rishabhrathod01 Nov 29, 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
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,15 @@ public class OnLoadSpanCE {
public static final String EXECUTABLE_IN_CREATOR_CONTEXT = APPSMITH_SPAN_PREFIX + "executablesInCreatorContext";
public static final String ADD_DIRECTLY_REFERENCED_EXECUTABLES_TO_GRAPH =
APPSMITH_SPAN_PREFIX + "addDirectlyReferencedExecutablesToGraph";
public static final String GET_POSSIBLE_ENTITY_REFERENCES = APPSMITH_SPAN_PREFIX + "getPossibleEntityReferences";
public static final String UPDATE_EXECUTABLE_SELF_REFERENCING_PATHS =
APPSMITH_SPAN_PREFIX + "updateExecutableSelfReferencingPaths";
public static final String GET_POSSIBLE_ENTITY_PARENTS_MAP = APPSMITH_SPAN_PREFIX + "getPossibleEntityParentsMap";
public static final String ADD_EXPLICIT_USER_SET_ON_LOAD_EXECUTABLES_TO_GRAPH =
APPSMITH_SPAN_PREFIX + "addExplicitUserSetOnLoadExecutablesToGraph";
public static final String GET_UNPUBLISHED_ON_LOAD_EXECUTABLES_EXPLICIT_SET_BY_USER_IN_CREATOR_CONTEXT =
APPSMITH_SPAN_PREFIX + "getUnpublishedOnLoadExecutablesExplicitSetByUserInCreatorContext";

public static final String GET_POSSIBLE_REFERENCES_FROM_DYNAMIC_BINDING =
APPSMITH_SPAN_PREFIX + "getPossibleReferencesFromDynamicBinding";
}
Original file line number Diff line number Diff line change
Expand Up @@ -524,9 +524,8 @@ private Mono<Set<EntityDependencyNode>> getPossibleEntityReferences(
Set<EntityDependencyNode> bindingsInDsl) {
// We want to be finding both type of references
final int entityTypes = EXECUTABLE_ENTITY_REFERENCES | WIDGET_ENTITY_REFERENCES;

return executableNameToExecutableMono
.zipWith(getPossibleEntityParentsMap(bindings, entityTypes, evalVersion))
.zipWith(getPossibleEntityParentsMap(new ArrayList<>(bindings), entityTypes, evalVersion))
.map(tuple -> {
Map<String, Executable> executableMap = tuple.getT1();
// For each binding, here we receive a set of possible references to global entities
Expand Down Expand Up @@ -584,6 +583,79 @@ private Mono<Set<EntityDependencyNode>> getPossibleEntityReferences(
});
}

// Create a method that accept widgetDynamicBindingsMap and return a map of widget path to set of possible entities
// This method will be used to find all possible global entity references in the given set of bindings.
// We'll be able to find valid executable references only at this point. For widgets, we just assume that all
// references are possible candidates

private Mono<Map<String, Set<EntityDependencyNode>>> getWidgetPathToPossibleEntitiesReferencesMap(
Mono<Map<String, Executable>> executableNameToExecutableMono,
Map<String, Set<String>> widgetDynamicBindingsMap,
int evalVersion,
Set<EntityDependencyNode> bindingsInDsl) {
final int entityTypes = EXECUTABLE_ENTITY_REFERENCES | WIDGET_ENTITY_REFERENCES;

Map<Number, String> indexToWidgetPathMap = new HashMap<>();
int bindingStartIndexInAllBindings = 0;
List<String> allBindings = new ArrayList<>();
for (Map.Entry<String, Set<String>> entry : widgetDynamicBindingsMap.entrySet()) {
String widgetPath = entry.getKey();
Set<String> bindings = entry.getValue();
allBindings.addAll(bindings);
int numberOfBindingsInPath = bindings.size();
for (int i = bindingStartIndexInAllBindings;
i < bindingStartIndexInAllBindings + numberOfBindingsInPath;
i++) {
indexToWidgetPathMap.put(i, widgetPath);
}
bindingStartIndexInAllBindings = bindingStartIndexInAllBindings + numberOfBindingsInPath;
}

return executableNameToExecutableMono
.zipWith(getPossibleEntityParentsMap(allBindings, entityTypes, evalVersion))
.map(tuple -> {
Map<String, Executable> executableMap = tuple.getT1();
Map<String, Set<EntityDependencyNode>> bindingToPossibleParentMap = tuple.getT2();
Map<String, Set<EntityDependencyNode>> widgetPathToPossibleEntitiesReferences = new HashMap<>();

final int[] currentIndex = {0};
bindingToPossibleParentMap.entrySet().stream().forEach(entry -> {
Set<EntityDependencyNode> bindingsWithExecutableReference = new HashSet<>();
Set<EntityDependencyNode> possibleEntitiesReferences = new HashSet<>();
String widgetPath = indexToWidgetPathMap.get(currentIndex[0]);

entry.getValue().stream().forEach(possibleParent -> {
Executable executable = executableMap.get(possibleParent.getValidEntityName());
if (executable != null) {
if (possibleParent
.getEntityReferenceType()
.equals(executable.getEntityReferenceType())) {
possibleParent.setExecutable(executable);
bindingsWithExecutableReference.add(possibleParent);
if (!TRUE.equals(possibleParent.getIsFunctionCall())) {
possibleEntitiesReferences.add(possibleParent);
}
}
} else {
if (EntityReferenceType.WIDGET.equals(possibleParent.getEntityReferenceType())) {
possibleEntitiesReferences.add(possibleParent);
}
}
});

widgetPathToPossibleEntitiesReferences.put(widgetPath, possibleEntitiesReferences);

if (!bindingsWithExecutableReference.isEmpty() && bindingsInDsl != null) {
bindingsInDsl.addAll(bindingsWithExecutableReference);
}

currentIndex[0] = currentIndex[0] + 1;
});

return widgetPathToPossibleEntitiesReferences;
});
}
rishabhrathod01 marked this conversation as resolved.
Show resolved Hide resolved

/**
* This method is an abstraction that queries the ast service for possible global references as string values,
* and then uses the mustache helper utility to classify these global references into possible types of EntityDependencyNodes
Expand All @@ -594,9 +666,9 @@ private Mono<Set<EntityDependencyNode>> getPossibleEntityReferences(
* @return A mono of a map of each of the provided binding values to the possible set of EntityDependencyNodes found in the binding
*/
private Mono<Map<String, Set<EntityDependencyNode>>> getPossibleEntityParentsMap(
Set<String> bindings, int types, int evalVersion) {
List<String> bindings, int types, int evalVersion) {
Flux<Tuple2<String, Set<String>>> findingToReferencesFlux =
astService.getPossibleReferencesFromDynamicBinding(new ArrayList<>(bindings), evalVersion);
astService.getPossibleReferencesFromDynamicBinding(bindings, evalVersion);
return MustacheHelper.getPossibleEntityParentsMap(findingToReferencesFlux, types);
}

Expand Down Expand Up @@ -627,51 +699,43 @@ private Mono<Set<ExecutableDependencyEdge>> addDirectlyReferencedExecutablesToGr
Mono<Map<String, Executable>> executableNameToExecutableMapMono,
Set<EntityDependencyNode> executableBindingsInDslRef,
int evalVersion) {
return Flux.fromIterable(widgetDynamicBindingsMap.entrySet())
return getWidgetPathToPossibleEntitiesReferencesMap(
executableNameToExecutableMapMono,
widgetDynamicBindingsMap,
evalVersion,
executableBindingsInDslRef)
.flatMapMany(widgetPathToPossibleEntitiesReferences ->
Flux.fromIterable(widgetPathToPossibleEntitiesReferences.entrySet()))
.flatMap(entry -> {
String widgetName = entry.getKey();
// For each widget in the DSL that has a dynamic binding,
// we define an entity dependency node beforehand
// This will be a leaf node in the DAG that is constructed for on page load dependencies
EntityDependencyNode widgetDependencyNode =
new EntityDependencyNode(EntityReferenceType.WIDGET, widgetName, widgetName, null, null);
Set<String> bindingsInWidget = entry.getValue();
return getPossibleEntityReferences(
executableNameToExecutableMapMono,
bindingsInWidget,
evalVersion,
executableBindingsInDslRef)
.flatMapMany(Flux::fromIterable)
// Add dependencies of the executables found in the DSL in the graph
// We are ignoring the widget references at this point
// TODO: Possible optimization in the future
.flatMap(possibleEntity -> {
if (getExecutableTypes().contains(possibleEntity.getEntityReferenceType())) {
edgesRef.add(new ExecutableDependencyEdge(possibleEntity, widgetDependencyNode));
// This executable is directly referenced in the DSL. This executable is an ideal
rishabhrathod01 marked this conversation as resolved.
Show resolved Hide resolved
// candidate
// for on page load
executablesUsedInDSLRef.add(possibleEntity.getValidEntityName());
return updateExecutableSelfReferencingPaths(possibleEntity)
.name(UPDATE_EXECUTABLE_SELF_REFERENCING_PATHS)
.tap(Micrometer.observation(observationRegistry))
.flatMap(executable -> extractAndSetExecutableBindingsInGraphEdges(
possibleEntity,
edgesRef,
bindingsFromExecutablesRef,
executableNameToExecutableMapMono,
executablesFoundDuringWalkRef,
null,
evalVersion))
.name(EXTRACT_AND_SET_EXECUTABLE_BINDINGS_IN_GRAPH_EDGES)
.tap(Micrometer.observation(observationRegistry))
.thenReturn(possibleEntity);
}
return Mono.just(possibleEntity);
});
String widgetPropertyPath = entry.getKey();
EntityDependencyNode widgetDependencyNode = new EntityDependencyNode(
EntityReferenceType.WIDGET, widgetPropertyPath, widgetPropertyPath, null, null);
Set<EntityDependencyNode> possibleEntities = entry.getValue();

return Flux.fromIterable(possibleEntities).flatMap(possibleEntity -> {
if (getExecutableTypes().contains(possibleEntity.getEntityReferenceType())) {
edgesRef.add(new ExecutableDependencyEdge(possibleEntity, widgetDependencyNode));
executablesUsedInDSLRef.add(possibleEntity.getValidEntityName());
return updateExecutableSelfReferencingPaths(possibleEntity)
.name(UPDATE_EXECUTABLE_SELF_REFERENCING_PATHS)
.tap(Micrometer.observation(observationRegistry))
.flatMap(executable -> extractAndSetExecutableBindingsInGraphEdges(
possibleEntity,
edgesRef,
bindingsFromExecutablesRef,
executableNameToExecutableMapMono,
executablesFoundDuringWalkRef,
null,
evalVersion))
.name(EXTRACT_AND_SET_EXECUTABLE_BINDINGS_IN_GRAPH_EDGES)
.tap(Micrometer.observation(observationRegistry))
.thenReturn(possibleEntity);
}
return Mono.just(possibleEntity);
});
})
.collectList()
.thenReturn(edgesRef);
.collectList() // Collect all emitted elements into a list (to complete processing of the Flux)
.then(Mono.just(edgesRef)); // Return edgesRef as Mono
}

protected Mono<Executable> updateExecutableSelfReferencingPaths(EntityDependencyNode possibleEntity) {
Expand Down Expand Up @@ -1134,7 +1198,7 @@ private Mono<Set<ExecutableDependencyEdge>> addWidgetRelationshipToGraph(
// This part will ensure that we are discovering widget to widget relationships.
return Flux.fromIterable(widgetBindingMap.entrySet())
.flatMap(widgetBindingEntries -> getPossibleEntityParentsMap(
widgetBindingEntries.getValue(), entityTypes, evalVersion)
new ArrayList<>(widgetBindingEntries.getValue()), entityTypes, evalVersion)
.map(possibleParentsMap -> {
possibleParentsMap.entrySet().stream().forEach(entry -> {
if (entry.getValue() == null || entry.getValue().isEmpty()) {
Expand Down
Loading
Loading