MCPcopy Index your code
hub / github.com/promptfoo/promptfoo / executeCall

Method executeCall

src/python/worker.ts:138–220  ·  view source on GitHub ↗
(functionName: string, args: unknown[])

Source from the content-addressed store, hash-verified

136 }
137
138 private async executeCall(functionName: string, args: unknown[]): Promise<unknown> {
139 let tempDirectory: string | undefined;
140
141 try {
142 tempDirectory = await createSecureTempDirectory('promptfoo-worker-');
143 const requestFile = await writeSecureTempFile(
144 tempDirectory,
145 'request.json',
146 safeJsonStringify(args) as string,
147 );
148 const responseFile = await writeSecureTempFile(tempDirectory, 'response.json', '');
149
150 // Send CALL command with function name
151 // Note: PythonShell.send() adds newline automatically in 'text' mode
152 // Using pipe (|) delimiter to avoid conflicts with Windows drive letters (C:)
153 const command = `CALL|${functionName}|${requestFile}|${responseFile}`;
154 this.process!.send(command);
155
156 // Wait for DONE
157 await new Promise<unknown>((resolve, reject) => {
158 this.pendingRequest = { responseFile, resolve, reject };
159 });
160
161 // Read response with exponential backoff retry.
162 // Python verifies file readability before sending DONE, but OS-level delays may still occur.
163 let responseData: string | undefined;
164 let lastError: unknown;
165
166 // Exponential backoff: 1ms, 2ms, 4ms, 8ms, 16ms, 32ms, 64ms, 128ms, 256ms, 512ms, 1024ms, 2048ms, 4096ms, 5000ms (capped)...
167 // Total max wait: ~18 seconds (handles severe filesystem delays)
168 for (let attempt = 0, delay = 1; attempt < 16; attempt++, delay = Math.min(delay * 2, 5000)) {
169 try {
170 responseData = await fs.readFile(responseFile, 'utf-8');
171 if (attempt > 0) {
172 logger.debug(`Response file read succeeded on attempt ${attempt + 1}`);
173 }
174 break;
175 } catch (error: unknown) {
176 lastError = error;
177 if (error && typeof error === 'object' && 'code' in error && error.code === 'ENOENT') {
178 // File doesn't exist yet, wait and retry with exponential backoff.
179 await new Promise((resolve) => setTimeout(resolve, delay));
180 continue;
181 }
182 // Non-ENOENT error, don't retry.
183 throw error;
184 }
185 }
186
187 // If we exhausted all retries, throw with debugging info
188 if (!responseData) {
189 try {
190 const files = await fs.readdir(tempDirectory);
191 logger.error(
192 `Failed to read response file after 16 attempts (~18s). Expected: ${path.basename(responseFile)}, Found in temporary directory: ${files.join(', ')}`,
193 );
194 } catch {
195 logger.error(

Callers 1

callMethod · 0.95

Calls 7

writeSecureTempFileFunction · 0.90
safeJsonStringifyFunction · 0.90
errorMethod · 0.80
parseMethod · 0.80
sendMethod · 0.45

Tested by

no test coverage detected