diff --git a/src/CONST/index.ts b/src/CONST/index.ts index da294e4abb72..5d9f5b1a4d13 100755 --- a/src/CONST/index.ts +++ b/src/CONST/index.ts @@ -1799,6 +1799,7 @@ const CONST = { SPAN_OPEN_SEARCH_ROUTER: 'ManualOpenSearchRouter', SPAN_OPEN_CREATE_EXPENSE: 'ManualOpenCreateExpense', SPAN_SEND_MESSAGE: 'ManualSendMessage', + SPAN_SEQUENTIAL_QUEUE_COMMAND: 'SequentialQueueCommand', SPAN_NOT_FOUND_PAGE: 'ManualNotFoundPage', SPAN_SKELETON: 'ManualSkeleton', SPAN_NAVIGATION_ROOT_READY: 'NavigationRootReady', @@ -1835,6 +1836,7 @@ const CONST = { ATTRIBUTE_CANCELED: 'canceled', ATTRIBUTE_ROUTE_FROM: 'route_from', ATTRIBUTE_ROUTE_TO: 'route_to', + ATTRIBUTE_COMMAND_NAME: 'command_name', ATTRIBUTE_MIN_DURATION: 'min_duration', ATTRIBUTE_FINISHED_MANUALLY: 'finished_manually', ATTRIBUTE_SKELETON_PREFIX: 'skeleton.', diff --git a/src/libs/Network/SequentialQueue.ts b/src/libs/Network/SequentialQueue.ts index 373f1c76826e..c54ac856c95c 100644 --- a/src/libs/Network/SequentialQueue.ts +++ b/src/libs/Network/SequentialQueue.ts @@ -1,6 +1,7 @@ import type {OnyxKey, OnyxUpdate} from 'react-native-onyx'; import Onyx from 'react-native-onyx'; import {setIsOpenAppFailureModalOpen} from '@libs/actions/isOpenAppFailureModalOpen'; +import {endSpan, startSpan} from '@libs/telemetry/activeSpans'; import { deleteRequestsByIndices as deletePersistedRequestsByIndices, endRequestAndRemoveFromQueue as endPersistedRequestAndRemoveFromQueue, @@ -157,6 +158,19 @@ function process(): Promise { persistWhenOngoing: requestToProcess.persistWhenOngoing ?? false, }); + const commandSpanId = `${CONST.TELEMETRY.SPAN_SEQUENTIAL_QUEUE_COMMAND}_${requestToProcess.command}`; + // Skip tracking PusherPing — it fires every 30s as a heartbeat and would spam telemetry + const shouldTrackSpan = requestToProcess.command !== WRITE_COMMANDS.PUSHER_PING; + if (shouldTrackSpan) { + startSpan(commandSpanId, { + name: CONST.TELEMETRY.SPAN_SEQUENTIAL_QUEUE_COMMAND, + op: CONST.TELEMETRY.SPAN_SEQUENTIAL_QUEUE_COMMAND, + attributes: { + [CONST.TELEMETRY.ATTRIBUTE_COMMAND_NAME]: requestToProcess.command, + }, + }); + } + // Set the current request to a promise awaiting its processing so that getCurrentRequest can be used to take some action after the current request has processed. currentRequestPromise = processWithMiddleware(requestToProcess, true) .then((response) => { @@ -177,6 +191,7 @@ function process(): Promise { command: requestToProcess.command, remainingRequests: getAllPersistedRequests().length, }); + endSpan(commandSpanId); endPersistedRequestAndRemoveFromQueue(requestToProcess); if (requestToProcess.queueFlushedData) { @@ -216,6 +231,7 @@ function process(): Promise { errorName: error.name, errorMessage: error.message, }); + endSpan(commandSpanId); endPersistedRequestAndRemoveFromQueue(requestToProcess); sequentialQueueRequestThrottle.clear(); return process(); @@ -226,6 +242,7 @@ function process(): Promise { command: requestToProcess.command, }); Onyx.update(requestToProcess.failureData ?? []); + endSpan(commandSpanId); endPersistedRequestAndRemoveFromQueue(requestToProcess); sequentialQueueRequestThrottle.clear(); return process(); @@ -236,6 +253,7 @@ function process(): Promise { errorMessage: error.message, }); + endSpan(commandSpanId); rollbackOngoingPersistedRequest(); return sequentialQueueRequestThrottle .sleep(error, requestToProcess.command)