修复
This commit is contained in:
@@ -43,6 +43,10 @@ namespace app\common\service {
|
||||
|
||||
function config(string $name): array { return $GLOBALS['largeConfig']; }
|
||||
function microtime(bool $asFloat = false): float { return $GLOBALS['largeClock']; }
|
||||
function hrtime(bool $asNumber = false): int|array {
|
||||
$now = (int) round($GLOBALS['largeClock'] * 1000000000);
|
||||
return $asNumber ? $now : [intdiv($now, 1000000000), $now % 1000000000];
|
||||
}
|
||||
function curl_init(): \stdClass { return (object) ['errno' => 0, 'code' => 200]; }
|
||||
function curl_setopt_array(\stdClass $handle, array $options): bool { $handle->options = $options; return true; }
|
||||
function curl_exec(\stdClass $handle): string|bool {
|
||||
@@ -75,16 +79,35 @@ namespace app\common\service {
|
||||
}
|
||||
$duration = $scenario === 'extraction-deadline' && $extract ? 31.0
|
||||
: ($scenario === 'synthesis-deadline' ? 20.0 : 0.001);
|
||||
$streaming = ($payload['response_mode'] ?? '') === 'streaming';
|
||||
$headerSent = false;
|
||||
if ($streaming && $handle->code === 200) {
|
||||
($options[CURLOPT_HEADERFUNCTION])($handle, "HTTP/1.1 200 Synthetic\r\n");
|
||||
$headerSent = true;
|
||||
($options[CURLOPT_WRITEFUNCTION])($handle, 'data: ' . json_encode([
|
||||
'event' => 'workflow_started', 'task_id' => 'large-task-' . count($GLOBALS['largeRequests']),
|
||||
]) . "\n\n");
|
||||
}
|
||||
// Model the progress pump's monotonic generation deadline separately
|
||||
// from libcurl's larger, bounded stop/terminal-drain transport cap.
|
||||
$progress = $options[defined('CURLOPT_XFERINFOFUNCTION') ? CURLOPT_XFERINFOFUNCTION : CURLOPT_PROGRESSFUNCTION] ?? null;
|
||||
$advanceMs = min((int) round($duration * 1000), $limitMs);
|
||||
for ($elapsedMs = 0; $elapsedMs < $advanceMs;) {
|
||||
$stepMs = min(100, $advanceMs - $elapsedMs);
|
||||
$GLOBALS['largeClock'] += $stepMs / 1000;
|
||||
$elapsedMs += $stepMs;
|
||||
if (is_callable($progress) && $progress($handle, 0, 0, 100, 100)) {
|
||||
$handle->errno = CURLE_ABORTED_BY_CALLBACK;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if ($duration * 1000 >= $limitMs) {
|
||||
$GLOBALS['largeClock'] += $limitMs / 1000;
|
||||
$handle->errno = CURLE_OPERATION_TIMEDOUT; $handle->code = 0;
|
||||
return false;
|
||||
}
|
||||
$GLOBALS['largeClock'] += $duration;
|
||||
if (isset($options[CURLOPT_HEADERFUNCTION])) {
|
||||
if (!$headerSent && isset($options[CURLOPT_HEADERFUNCTION])) {
|
||||
($options[CURLOPT_HEADERFUNCTION])($handle, 'HTTP/1.1 ' . $handle->code . " Synthetic\r\n");
|
||||
}
|
||||
$streaming = ($payload['response_mode'] ?? '') === 'streaming';
|
||||
if ($error !== null) {
|
||||
$body = json_encode($error);
|
||||
if ($streaming) { ($options[CURLOPT_WRITEFUNCTION])($handle, $body); return true; }
|
||||
@@ -114,6 +137,7 @@ namespace app\common\service {
|
||||
}
|
||||
|
||||
namespace {
|
||||
require_once dirname(__DIR__) . '/app/common/service/DifyReasoningTextFilter.php';
|
||||
require dirname(__DIR__) . '/app/common/service/DifyChatService.php';
|
||||
use app\common\service\DifyChatService;
|
||||
|
||||
@@ -143,6 +167,7 @@ namespace {
|
||||
$GLOBALS['largeScenario'] = $scenario; $GLOBALS['largeClock'] = 1000.0;
|
||||
$GLOBALS['largeRequests'] = []; $GLOBALS['largeUploads'] = []; $GLOBALS['largeLogs'] = [];
|
||||
$GLOBALS['largeExtracts'] = 0; $GLOBALS['largeStops'] = 0; $GLOBALS['largeCancelled'] = false;
|
||||
$GLOBALS['largeTimeoutClock'] = null;
|
||||
$GLOBALS['largeMissing'] = [];
|
||||
$GLOBALS['largeConfig'] = ['enable' => true, 'base_url' => 'https://synthetic.invalid/v1/chat-messages',
|
||||
'timeout' => 90, 'required_attachment_transport' => 'upload', 'max_files' => 3,
|
||||
@@ -154,6 +179,7 @@ namespace {
|
||||
['key' => 'basic_info', 'status' => 'prepared', 'availability' => 'present'],
|
||||
['key' => 'chat', 'status' => 'prepared', 'availability' => 'present'],
|
||||
], 'on_progress' => static function (array $event) use (&$events): void { $events[] = $event; },
|
||||
'on_timeout' => static function (): void { $GLOBALS['largeTimeoutClock'] = $GLOBALS['largeClock']; },
|
||||
'on_task' => static function (...$args) use (&$tasks): void { $tasks[] = $args; },
|
||||
'on_transfer_end' => static function (...$args) use (&$ends): void { $ends[] = $args; }];
|
||||
$inputs = ['full_original_inputs' => $query];
|
||||
@@ -232,10 +258,13 @@ namespace {
|
||||
['result' => $result, 'deltas' => $deltas, 'events' => $events] = largeRun(largeFiles(40), $streaming);
|
||||
largeExpect(empty($result['ok']) && $result['error_code'] === 'UPSTREAM_TIMEOUT', 'whole shared 90-second budget also constrains final synthesis');
|
||||
$expected = $scenario === 'extraction-deadline' ? 3 : 5;
|
||||
largeExpect(count($largeRequests) === $expected && abs($largeClock - 1090.0) < 0.01,
|
||||
'later batches do not receive fresh ninety-second budgets');
|
||||
largeExpect($largeRequests[count($largeRequests) - 1]['limitMs'] <= ($scenario === 'extraction-deadline' ? 28000 : 10000),
|
||||
'real curl millisecond option receives remaining aggregate budget');
|
||||
largeExpect(count($largeRequests) === $expected
|
||||
&& ($streaming ? abs($largeTimeoutClock - 1090.0) < 0.01 && $largeClock <= 1092.51
|
||||
: abs($largeClock - 1090.0) < 0.01),
|
||||
'later batches share ninety seconds of generation; only bounded stop/terminal draining may follow');
|
||||
largeExpect($largeRequests[count($largeRequests) - 1]['limitMs']
|
||||
<= ($scenario === 'extraction-deadline' ? 28000 : 10000) + ($streaming ? 2500 : 0),
|
||||
'curl cap is the remaining aggregate generation budget plus streaming cleanup, never a fresh budget');
|
||||
largeExpect($deltas === [], 'no extracted intermediate evidence is promoted to partial clinical answer on timeout');
|
||||
largeSafe($result, $events); $cases++;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user