Skip to content

Commit bb0bd9f

Browse files
icecrasher321claude
andcommitted
improvement(webhooks): decompose dispatch latency into phase timings + executor-start metric
The "Webhook dispatch latency" line now carries preprocessMs/loadsMs/ providerConfigMs/formatInputMs, and a one-shot onBlockStart callback logs "Webhook executor started" with the true trigger age when the first block runs — the moment that decides a trigger_id-bound provider's 3s race, which the existing metric (emitted before executeWorkflowCore) undercounts. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent f1a3456 commit bb0bd9f

1 file changed

Lines changed: 34 additions & 1 deletion

File tree

apps/sim/background/webhook-execution.ts

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,7 @@ async function executeWebhookJobInternal(
493493
)
494494
loggingSession.setExecutionDeadlineAt(getExecutionDeadlineAt(timeoutController.signal))
495495

496+
const preprocessStartedAt = Date.now()
496497
const preprocessResult = await preprocessExecution({
497498
workflowId: payload.workflowId,
498499
userId: payload.userId,
@@ -509,6 +510,7 @@ async function executeWebhookJobInternal(
509510
executionType: 'async',
510511
executionDeadlineAt: getExecutionDeadlineAt(timeoutController.signal)?.getTime(),
511512
})
513+
const preprocessEndedAt = Date.now()
512514

513515
if (!preprocessResult.success) {
514516
throw new Error(preprocessResult.error?.message || 'Preprocessing failed in background job')
@@ -564,6 +566,7 @@ async function executeWebhookJobInternal(
564566
? resolveCredentialAccountUserId(payload.credentialId)
565567
: Promise.resolve(undefined),
566568
])
569+
const loadsEndedAt = Date.now()
567570
const credentialAccountUserId = resolvedCredentialUserId
568571
if (payload.credentialId && !credentialAccountUserId) {
569572
logger.warn(
@@ -626,6 +629,7 @@ async function executeWebhookJobInternal(
626629
},
627630
}
628631
)
632+
const providerConfigEndedAt = Date.now()
629633

630634
if (handler.formatInput) {
631635
const result = await handler.formatInput({
@@ -642,6 +646,7 @@ async function executeWebhookJobInternal(
642646
} else {
643647
input = payload.body as Record<string, unknown> | null
644648
}
649+
const formatInputEndedAt = Date.now()
645650

646651
if (!input && handler.handleEmptyInput) {
647652
const skipResult = handler.handleEmptyInput(requestId)
@@ -791,6 +796,10 @@ async function executeWebhookJobInternal(
791796
payload.webhookReceivedAt !== undefined ? now - payload.webhookReceivedAt : undefined,
792797
triggerAgeMs:
793798
payload.triggerTimestampMs !== undefined ? now - payload.triggerTimestampMs : undefined,
799+
preprocessMs: preprocessEndedAt - preprocessStartedAt,
800+
loadsMs: loadsEndedAt - preprocessEndedAt,
801+
providerConfigMs: providerConfigEndedAt - loadsEndedAt,
802+
formatInputMs: formatInputEndedAt - providerConfigEndedAt,
794803
})
795804
}
796805

@@ -802,9 +811,33 @@ async function executeWebhookJobInternal(
802811
[]
803812
)
804813

814+
/**
815+
* The dispatch-latency line above fires before executeWorkflowCore, so it cannot
816+
* see the core's own setup (custom-block gate, env resolution, logging start,
817+
* serialization). This logs once, when the first block actually starts — the
818+
* moment that decides a trigger_id-bound provider's race against its expiry.
819+
*/
820+
let executorStartLogged = false
821+
const logExecutorStart = async () => {
822+
if (executorStartLogged) return
823+
executorStartLogged = true
824+
if (payload.webhookReceivedAt === undefined && payload.triggerTimestampMs === undefined) {
825+
return
826+
}
827+
const now = Date.now()
828+
logger.info(`[${requestId}] Webhook executor started`, {
829+
workflowId: payload.workflowId,
830+
provider: payload.provider,
831+
executorStartLatencyMs:
832+
payload.webhookReceivedAt !== undefined ? now - payload.webhookReceivedAt : undefined,
833+
executorStartTriggerAgeMs:
834+
payload.triggerTimestampMs !== undefined ? now - payload.triggerTimestampMs : undefined,
835+
})
836+
}
837+
805838
const executionResult = await executeWorkflowCore({
806839
snapshot,
807-
callbacks: {},
840+
callbacks: { onBlockStart: logExecutorStart },
808841
loggingSession,
809842
trustedInitialResolvedSecretTraceProvenance:
810843
resolvedSecretTraceRegistry.exportProvenanceForValue(triggerInput),

0 commit comments

Comments
 (0)