You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Graph API写入Excel异常:正常运行一段时间后失效

问题分析与解决方案

核心问题定位

你的问题(网页版Excel无法打开、Graph API写入失败,桌面版正常,复制文件后恢复),大概率是Graph API工作簿会话未正确释放导致的文件锁定。即使代码中调用了closeSession,仍可能存在会话残留的情况。

代码中的潜在问题

  1. 会话关闭可靠性不足

    • 当前close_session1仅判断请求是否报错,但Graph API的closeSession可能返回成功状态但实际会话未释放(比如网络波动导致请求未到达服务器)。
    • 未处理create_session1返回false的场景,若会话创建失败,后续操作会以无会话模式执行,隐式创建的临时会话无法自动释放。
  2. 错误处理缺失导致会话泄漏

    • get_clients_from_tb1中,若post_data_to_excel1或delete_rows_not_in_data1执行出错,流程会直接终止,close_session1无法被调用,会话永久残留。
  3. 变量与会话ID传递错误

    • get_clients_from_tb1的Authorization头使用了未定义的$Token变量,应该传入函数参数$accessToken;
    • 需确认post_data_to_excel1和delete_rows_not_in_data1是否在请求头中正确携带Workbook-Session-Id,未携带会导致Graph API自动创建新会话,引发会话溢出。

修复方案

1. 优化会话关闭逻辑(增加重试与状态校验)

修改close_session1,确保会话可靠关闭:

function close_session1($token, $sessionId, $retryTimes = 2) {
    $closeSessionUrl = "https://graph.microsoft.com/v1.0/users/{userid}/drive/items/{id}/workbook/closeSession";
    $success = false;
    
    for ($i = 0; $i <= $retryTimes; $i++) {
        $closeSessionResponse = wp_remote_request($closeSessionUrl, [
            'method' => 'POST',
            'headers' => [
                'Authorization' => "Bearer $token",
                'Workbook-Session-Id' => $sessionId,
            ],
        ]);

        if (!is_wp_error($closeSessionResponse)) {
            $statusCode = wp_remote_retrieve_response_code($closeSessionResponse);
            if ($statusCode >= 200 && $statusCode < 300) {
                $success = true;
                break;
            }
        }
        sleep(1); // 重试前等待1秒
    }

    if (!$success) {
        error_log("Failed to close session after $retryTimes retries: Session ID $sessionId");
    }
    return $success;
}

2. 全局异常捕获,保证会话必关

修改get_clients_from_tb1,用try...finally确保无论中间是否出错,会话都会被关闭:

function get_clients_from_tb1($accessToken){
    $sessionid = null;
    try {
        $args = array(
            'headers' => array(
                'Authorization'=> "Bearer $accessToken", // 修复变量错误
            ),
        );

        $apiUrl = 'https://system.easypractice.net/api/v1/clients?page_size=500';
        $response = wp_remote_get($apiUrl, $args);
        if (is_wp_error($response)) {
            $error_message = $response->get_error_message();
            error_log("Something went wrong1: $error_message");
            return;
        }

        $status = wp_remote_retrieve_response_code($response);
        if ($status !== 200) {
            error_log("Received HTTP status code: $status");
            return;
        }

        $data = json_decode(wp_remote_retrieve_body($response), true);
        $all_client_ids_from_tb = array();

        if (isset($data['data']) && is_array($data['data'])) {
            $sessionid = create_session1($accessToken);
            if (!$sessionid) {
                error_log("Failed to create workbook session");
                return;
            }
            foreach ($data['data'] as $client_data) {
                $all_client_ids_from_tb[] = $client_data['id'];
                post_data_to_excel1($accessToken,$client_data,$sessionid);      
            }
            delete_rows_not_in_data1($accessToken,$all_client_ids_from_tb,$sessionid);
        }
    } catch (Exception $e) {
        error_log("Unexpected error in get_clients_from_tb1: " . $e->getMessage());
    } finally {
        if ($sessionid) {
            close_session1($accessToken,$sessionid);
        }
    }
}

3. 强制清理残留会话

如果文件已经被锁定,调用以下函数列出并关闭所有残留会话:

function list_and_close_all_sessions($token) {
    $listSessionsUrl = "https://graph.microsoft.com/v1.0/users/{userid}/drive/items/{id}/workbook/sessions";
    $response = wp_remote_get($listSessionsUrl, [
        'headers' => [
            'Authorization' => "Bearer $token",
        ],
    ]);

    if (!is_wp_error($response)) {
        $sessions = json_decode(wp_remote_retrieve_body($response), true);
        if (isset($sessions['value'])) {
            foreach ($sessions['value'] as $session) {
                close_session1($token, $session['id']);
            }
        }
    }
}

可在cron任务开头调用此函数,定期清理会话。

4. 权限与文件配置检查

  • 确认Azure应用已授予Files.ReadWrite.All或Sites.ReadWrite.All权限;
  • 检查SharePoint文件属性,确保未设置为仅允许桌面版编辑。

预防措施

  • 每次cron任务仅创建一个会话,操作完成后立即关闭;
  • 增加会话创建、关闭的日志记录,便于排查问题;
  • 定期监控文件会话数量,避免会话溢出导致锁定。

内容的提问来源于stack exchange,提问作者Oliver - bbh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 19:43:14