MCPcopy
hub / github.com/simstudioai/sim / emitExecutionCompletedEvent

Function emitExecutionCompletedEvent

apps/sim/lib/workspace-events/emitter.ts:87–162  ·  view source on GitHub ↗
(log: WorkflowExecutionLog)

Source from the content-addressed store, hash-verified

85 * itself never emit (loop prevention).
86 */
87export async function emitExecutionCompletedEvent(log: WorkflowExecutionLog): Promise<void> {
88 try {
89 if (!log.workflowId) return
90 if (log.trigger === SIM_TRIGGER_PROVIDER) return
91
92 const workflowContext = await getActiveWorkflowContext(log.workflowId)
93 if (!workflowContext?.workspaceId) return
94
95 const subscriptions = await fetchSimTriggerSubscriptions(workflowContext.workspaceId)
96 if (subscriptions.length === 0) return
97
98 const executionData = (log.executionData ?? {}) as Record<string, unknown>
99 const context: ExecutionEventContext = {
100 workflowId: log.workflowId,
101 executionId: log.executionId,
102 status: log.level === 'error' ? 'error' : 'success',
103 durationMs: log.totalDurationMs || 0,
104 cost: (log.cost as { total?: number } | undefined)?.total || 0,
105 finalOutput: executionData.finalOutput,
106 }
107
108 for (const subscription of subscriptions) {
109 const config = parseSubscriptionConfig(subscription.webhook.providerConfig)
110 if (!config) continue
111 if (config.eventType === 'workflow_deployed') continue
112 // no_activity is owned by the inactivity poller and can never fire from
113 // a completed execution; skip before the rule branch costs a cooldown
114 // read on this hot path.
115 if (config.eventType === 'no_activity') continue
116
117 if (subscription.webhook.workflowId === log.workflowId) continue
118 if (!matchesWorkflowScope(config, log.workflowId)) continue
119
120 if (config.eventType === 'execution_success' && context.status !== 'success') continue
121 if (config.eventType === 'execution_error' && context.status !== 'error') continue
122
123 if (isSimRuleEventType(config.eventType)) {
124 const blockKey = subscriptionBlockKey(subscription)
125
126 const lastFiredAt = await readLastFiredAt(subscription.webhook.workflowId, blockKey, '')
127 if (isWithinCooldown(lastFiredAt, SIM_RULE_COOLDOWN_MS)) continue
128
129 const ruleFired = await evaluateRule(config.eventType, config, context)
130 if (!ruleFired) continue
131
132 const claimed = await claimCooldown(
133 subscription.webhook.workflowId,
134 blockKey,
135 '',
136 SIM_RULE_COOLDOWN_MS
137 )
138 if (!claimed) continue
139
140 logger.info(`Sim trigger rule ${config.eventType} fired`, {
141 subscriberWorkflowId: subscription.webhook.workflowId,
142 sourceWorkflowId: log.workflowId,
143 executionId: log.executionId,
144 })

Callers 2

emitter.test.tsFile · 0.90

Calls 14

getActiveWorkflowContextFunction · 0.90
parseSubscriptionConfigFunction · 0.90
isSimRuleEventTypeFunction · 0.90
readLastFiredAtFunction · 0.90
isWithinCooldownFunction · 0.90
evaluateRuleFunction · 0.90
claimCooldownFunction · 0.90
matchesWorkflowScopeFunction · 0.85
subscriptionBlockKeyFunction · 0.85
dispatchSimEventFunction · 0.85

Tested by

no test coverage detected