MCPcopy Create free account
hub / github.com/langgenius/dify / execute

Function execute

cli/src/http/client.ts:146–264  ·  view source on GitHub ↗
(
  state: ClientState,
  request: Request,
  resolved: ResolvedOptions,
  effectiveTimeoutMs: number | undefined,
  userSignal: AbortSignal | undefined,
)

Source from the content-addressed store, hash-verified

144// low-level `request` entrypoint (oRPC's pre-built Request) share one retry/timeout
145// /error policy.
146async function execute(
147 state: ClientState,
148 request: Request,
149 resolved: ResolvedOptions,
150 effectiveTimeoutMs: number | undefined,
151 userSignal: AbortSignal | undefined,
152): Promise<Response> {
153 const { method, retryAttempts: effectiveRetryAttempts, throwOnError } = resolved
154
155 for (let attempt = 0; ; attempt++) {
156 // Fresh timeout budget per attempt, merged with the persistent user/oRPC signal.
157 // Mirrors the old recursion that re-ran buildSignal() on every retry. Keep this
158 // INSIDE the loop — hoisting it would leak attempt 0's timeout into later attempts.
159 const signal = mergeSignal(userSignal, effectiveTimeoutMs)
160
161 // clone-on-retry: the first fetch consumes the Request body, so any attempt that
162 // may still be retried sends a clone and keeps `request` as the pristine replay copy.
163 const sendable = attempt < effectiveRetryAttempts ? request.clone() : request
164
165 const ctx: FetchContext = {
166 request: sendable,
167 options: resolved,
168 attempt,
169 meta: new Map(),
170 }
171
172 await runHooks(state.hooks.onRequest, ctx)
173
174 const init: RequestInit & { dispatcher?: unknown, verbose?: boolean } = { signal }
175 if (state.dispatcher !== undefined)
176 init.dispatcher = state.dispatcher
177 if (isVerbose())
178 init.verbose = true
179
180 try {
181 ctx.response = await fetch(ctx.request, init)
182 }
183 catch (err) {
184 ctx.error = err
185 // Snapshot the abort cause before onRequestError hooks rewrite ctx.error into BaseError.
186 const userAborted = userSignal?.aborted === true
187 await runHooks(state.hooks.onRequestError, ctx)
188
189 // User aborts (ctrl+C) must never retry. Timeouts and other transport errors fall
190 // through to shouldRetry, which enforces the method allowlist.
191 if (!userAborted && attempt < effectiveRetryAttempts && shouldRetry(ctx.error, ctx)) {
192 state.logger?.({ phase: 'retry', method, url: redactBearer(ctx.request.url), attempt: attempt + 1 })
193 const delay = backoffDelay(attempt + 1)
194 if (delay > 0)
195 await new Promise(resolve => setTimeout(resolve, delay))
196 continue
197 }
198
199 const finalErr = ctx.error
200 if (finalErr instanceof Error && typeof Error.captureStackTrace === 'function')
201 Error.captureStackTrace(finalErr, execute)
202 throw finalErr
203 }

Callers 5

typedCallFunction · 0.85
rawFetchFunction · 0.85
streamFetchFunction · 0.85
requestFetchFunction · 0.85

Calls 14

isVerboseFunction · 0.90
shouldRetryFunction · 0.90
mergeSignalFunction · 0.85
runHooksFunction · 0.85
fetchFunction · 0.85
redactBearerFunction · 0.85
backoffDelayFunction · 0.85
classifyRateLimitFunction · 0.85
isIdempotentRetryMethodFunction · 0.85
rateLimitDelayMsFunction · 0.85
classifyResponseFunction · 0.85
cloneMethod · 0.45

Tested by

no test coverage detected