Google Retail API SetInventory操作PollUntilCompleted抛出无效操作异常
Google Retail API
PollUntilCompleted() 报错 "Operation has not completed." 解决指南 问题概述
在使用Google Retail API设置产品库存时,调用PollUntilCompleted()同步方法抛出System.InvalidOperationException,错误提示为"Operation has not completed."。同时调用AddLocalInventoriesAsync方法时也出现相同异常,但产品创建操作可正常完成。
异常详情
- 异常类型:
System.InvalidOperationException - 错误消息:
"Operation has not completed." - 调试观测:
'operation.Result' threw an exception of type 'System.InvalidOperationException'
涉事核心代码
public static void SetProductInventory(string productName) { var setInventoryRequest = GetSetInventoryRequest(productName); var client = ProductServiceClient.Create(); var operation = client.SetInventory(setInventoryRequest); Console.WriteLine("Set inventory. Please, wait."); Console.WriteLine(); operation.PollUntilCompleted(); // 触发异常的代码行 } // 调用流程 public static void PerformSetInventoryOperation() { string projectId = Environment.GetEnvironmentVariable("GOOGLE_PROJECT_ID"); Product createdProduct = CreateProductSample.CreateRetailProductWithFulfillment(projectId); SetInventorySample.SetProductInventory(createdProduct.Name); // 调用库存设置方法 Product product = GetProductSample.GetRetailProduct(createdProduct.Name); Console.WriteLine($"Product Price Info: {product.PriceInfo}"); DeleteProductSample.DeleteRetailProduct(createdProduct.Name); }
解决方案
1. 替换为异步轮询方法
同步轮询易因主线程阻塞或超时设置不合理导致异常,改用异步版本:
// 修改库存设置方法为异步 public static async Task SetProductInventoryAsync(string productName) { var setInventoryRequest = GetSetInventoryRequest(productName); var client = ProductServiceClient.Create(); var operation = client.SetInventory(setInventoryRequest); Console.WriteLine("Set inventory. Please, wait."); Console.WriteLine(); await operation.PollUntilCompletedAsync(); } // 调用处同步改为异步 public static async Task PerformSetInventoryOperationAsync() { string projectId = Environment.GetEnvironmentVariable("GOOGLE_PROJECT_ID"); Product createdProduct = CreateProductSample.CreateRetailProductWithFulfillment(projectId); await SetInventorySample.SetProductInventoryAsync(createdProduct.Name); Product product = GetProductSample.GetRetailProduct(createdProduct.Name); Console.WriteLine($"Product Price Info: {product.PriceInfo}"); DeleteProductSample.DeleteRetailProduct(createdProduct.Name); }
2. 自定义轮询超时与间隔
默认轮询配置可能超时过短,手动指定合理的超时时间和轮询间隔:
// 设置30秒超时,每2秒轮询一次 operation.PollUntilCompleted(TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(2));
3. 增加产品创建后的延迟
产品创建后存在短暂的后端同步延迟,添加延迟确保产品状态稳定后再执行库存操作:
Product createdProduct = CreateProductSample.CreateRetailProductWithFulfillment(projectId); // 等待2秒确保产品同步完成 System.Threading.Thread.Sleep(2000); // 异步场景可使用await Task.Delay(2000) SetInventorySample.SetProductInventory(createdProduct.Name);
4. 检查操作状态再执行轮询
在轮询前先判断操作状态,避免对已失败的操作执行轮询:
if (!operation.IsCompleted) { try { operation.PollUntilCompleted(); } catch (InvalidOperationException ex) { Console.WriteLine($"轮询失败: {ex.Message}"); // 可根据需求尝试重新发起操作 } } else if (operation.IsFaulted) { Console.WriteLine($"操作已失败: {operation.Exception?.InnerException?.Message}"); }
5. 验证API权限与配额
- 确认当前服务账号拥有
Retail Editor或对应库存操作的权限 - 在Google Cloud控制台查看Retail API的配额使用情况,确认未触发调用限制
- 查看API日志,排查是否存在后端服务返回的隐藏错误
内容的提问来源于stack exchange,提问作者Ivan Meyer
相关产品推荐
相关产品推荐

