chore: remove analytics execution from the critical path (#39757)

## Description

- Pushed out the sendExecuteAnalyticsEvent from the critical path of
returning action's execution result.
- Improved the critical Path of sendExecuteAnalyticsEvent by running the
application mono concurrent to other events.
- Added more telemetry code around the execution flow.


Fixes #`Issue Number`  
_or_  
Fixes `Issue URL`
> [!WARNING]  
> _If no issue exists, please create an issue first, and check with the
maintainers if the issue is valid._

## Automation

/ok-to-test tags="@tag.All"

### 🔍 Cypress test results
<!-- This is an auto-generated comment: Cypress test results  -->
> [!TIP]
> 🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉
> Workflow run:
<https://github.com/appsmithorg/appsmith/actions/runs/13919689126>
> Commit: ddf93dd06cd4facabdde5898d1cc40ce7dc4765f
> <a
href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=13919689126&attempt=1"
target="_blank">Cypress dashboard</a>.
> Tags: `@tag.All`
> Spec:
> <hr>Tue, 18 Mar 2025 10:28:52 UTC
<!-- end of auto-generated comment: Cypress test results  -->


## Communication
Should the DevRel and Marketing teams inform users about this change?
- [ ] Yes
- [ ] No


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

- **New Features**
- Introduced additional action tracking identifiers to support enhanced
analytics and authentication validation.
- **Refactor**
- Optimized asynchronous operations for data retrieval to improve
responsiveness.
- Enhanced the flow and error handling of action execution, ensuring
smoother and more reliable performance.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
Vemparala Surya Vamsi 2025-03-18 17:21:50 +05:30 committed by GitHub
parent d494ca4ee1
commit 20317c5825
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 35 additions and 17 deletions

View File

@ -22,6 +22,12 @@ public class ActionSpanCE {
public static final String GET_ENVIRONMENT_ID = APPSMITH_SPAN_PREFIX + "getEnvironmentId";
public static final String POPULATED_EXECUTE_ACTION_DTO_MONO =
APPSMITH_SPAN_PREFIX + "populatedExecuteActionDTOMono";
public static final String VALIDATE_AUTHENTICATION_DATASOURCE_STORAGE =
APPSMITH_SPAN_PREFIX + "validateAuthenticationDatasourceStorage";
public static final String VERIFY_DATASOURCE_AND_MAKE_REQUEST =
APPSMITH_SPAN_PREFIX + "verifyDatasourceAndMakeRequest";
public static final String SEND_EXECUTE_ANALYTICS_EVENT = APPSMITH_SPAN_PREFIX + "sendExecuteAnalyticsEvent";
public static final String POPULATE_AND_EXECUTE_ACTION = APPSMITH_SPAN_PREFIX + "populateAndExecuteAction";
public static final String GET_VALID_ACTION_FOR_EXECUTION = APPSMITH_SPAN_PREFIX + "getValidActionForExecution";
public static final String GET_CACHED_PLUGIN_FOR_ACTION_EXECUTION =

View File

@ -68,6 +68,8 @@ import org.springframework.util.StringUtils;
import reactor.core.observability.micrometer.Micrometer;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;
import reactor.util.function.Tuple2;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
@ -360,6 +362,7 @@ public class ActionExecutionSolutionCEImpl implements ActionExecutionSolutionCE
: getCachedPluginForActionExecution(datasourceStorageMono)
.name(GET_CACHED_PLUGIN_FOR_ACTION_EXECUTION)
.tap(Micrometer.observation(observationRegistry));
Mono<PluginExecutor> pluginExecutorMono = pluginExecutorHelper
.getPluginExecutor(pluginMono)
.name(GET_PLUGIN_EXECUTOR)
@ -375,7 +378,6 @@ public class ActionExecutionSolutionCEImpl implements ActionExecutionSolutionCE
executeActionMetaDTO.getHeaders())
.name(GET_ACTION_EXECUTION_RESULT)
.tap(Micrometer.observation(observationRegistry));
Mono<Map> editorConfigLabelMapMono = getEditorConfigLabelMap(datasourceStorageMono);
return actionExecutionResultMono
@ -764,6 +766,8 @@ public class ActionExecutionSolutionCEImpl implements ActionExecutionSolutionCE
Mono<ActionExecutionResult> executionMono = authenticationValidator
.validateAuthentication(datasourceStorage)
.name(VALIDATE_AUTHENTICATION_DATASOURCE_STORAGE)
.tap(Micrometer.observation(observationRegistry))
.zipWhen(validatedDatasource -> datasourceContextService
.getDatasourceContext(validatedDatasource, plugin)
.tag("plugin", plugin.getPackageName())
@ -909,37 +913,45 @@ public class ActionExecutionSolutionCEImpl implements ActionExecutionSolutionCE
Mono<ActionDTO> actionDTOWithAutoGeneratedHeadersMono =
setAutoGeneratedHeaders(plugin, actionDTO, httpHeaders);
Mono<ActionExecutionResult> actionExecutionResultMono =
actionDTOWithAutoGeneratedHeadersMono.flatMap(actionDTO1 -> verifyDatasourceAndMakeRequest(
Mono<ActionExecutionResult> actionExecutionResultMono = actionDTOWithAutoGeneratedHeadersMono
.flatMap(actionDTO1 -> verifyDatasourceAndMakeRequest(
executeActionDTO, actionDTO, datasourceStorage, plugin, pluginExecutor)
.timeout(Duration.ofMillis(timeoutDuration)));
.timeout(Duration.ofMillis(timeoutDuration)))
.name(VERIFY_DATASOURCE_AND_MAKE_REQUEST)
.tap(Micrometer.observation(observationRegistry));
ActionConfiguration finalRawActionConfiguration = rawActionConfiguration;
return actionExecutionResultMono
.onErrorMap(executionExceptionMapper(actionDTO, timeoutDuration))
.onErrorResume(executionExceptionHandler(actionDTO))
.elapsed()
// Now send the analytics event for this execution
.flatMap(tuple1 -> {
.map(tuple1 -> {
Long timeElapsed = tuple1.getT1();
ActionExecutionResult result = tuple1.getT2();
log.debug(
"{}: Action {} with id {} execution time : {} ms",
Thread.currentThread().getName(),
actionDTO.getName(),
actionDTO.getId(),
timeElapsed);
return sendExecuteAnalyticsEvent(
return tuple1;
})
.doOnSuccess(tuple2 -> {
Long timeElapsed = tuple2.getT1();
ActionExecutionResult result = tuple2.getT2();
// Runs the analytics in the separate thread and immediately return the execution result
sendExecuteAnalyticsEvent(
actionDTO,
datasourceStorage,
executeActionDTO,
result,
timeElapsed,
finalRawActionConfiguration)
.thenReturn(result);
});
.name(SEND_EXECUTE_ANALYTICS_EVENT)
.tap(Micrometer.observation(observationRegistry))
.subscribeOn(Schedulers.boundedElastic())
.subscribe();
})
.map(Tuple2::getT2);
});
}
@ -1097,16 +1109,16 @@ public class ActionExecutionSolutionCEImpl implements ActionExecutionSolutionCE
request.setProperties(stringProperties);
}
return Mono.justOrEmpty(actionDTO.getApplicationId())
Mono<Application> applicationMono = Mono.justOrEmpty(actionDTO.getApplicationId())
.flatMap(applicationService::findById)
.defaultIfEmpty(new Application())
.flatMap(application -> Mono.zip(
Mono.just(application),
.defaultIfEmpty(new Application());
return Mono.zip(
applicationMono,
sessionUserService.getCurrentUser(),
newPageService.getNameByPageId(actionDTO.getPageId(), executeActionDto.getViewMode()),
pluginService.getByIdWithoutPermissionCheck(actionDTO.getPluginId()),
datasourceStorageService.getEnvironmentNameFromEnvironmentIdForAnalytics(
datasourceStorage.getEnvironmentId())))
datasourceStorage.getEnvironmentId()))
.flatMap(tuple -> {
final Application application = tuple.getT1();
final User user = tuple.getT2();