修复一些bug
This commit is contained in:
1 parent
9bb17a67d2
commit
f4913b4fc2
7 files changed
+38
-10
No files matched your search
@@ -8,6 +8,7 @@
|
|||||||
"MinimumLevel": {
|
"MinimumLevel": {
|
||||||
"Default": "Debug",
|
"Default": "Debug",
|
||||||
"Override": {
|
"Override": {
|
||||||
|
"MAX.Framework.Security.TokenAuthenticationHandler": "Information",
|
||||||
"Microsoft": "Information",
|
"Microsoft": "Information",
|
||||||
"Microsoft.AspNetCore": "Warning",
|
"Microsoft.AspNetCore": "Warning",
|
||||||
"System": "Warning",
|
"System": "Warning",
|
||||||
|
|||||||
@@ -36,11 +36,6 @@ namespace Store.Modules.CloudProduct
|
|||||||
// 服务自行创建客户端,单例复用连接池并由容器负责释放。
|
// 服务自行创建客户端,单例复用连接池并由容器负责释放。
|
||||||
services.AddSingleton<ImageAnalysisQuotaService>();
|
services.AddSingleton<ImageAnalysisQuotaService>();
|
||||||
|
|
||||||
// 图片识别沿用专用缓存库,所有请求共享并发上限。
|
|
||||||
var inspectionConnection = RequireConfiguration("ProductInspection:ConnectionString");
|
|
||||||
services.AddKeyedSingleton<IFreeSql>("ProductInspectionConnection", (_, _) =>
|
|
||||||
new FreeSql.FreeSqlBuilder().UseConnectionString(FreeSql.DataType.MySql, inspectionConnection)
|
|
||||||
.UseAdoConnectionPool(true).Build());
|
|
||||||
var maximum = Context.Configuration.GetValue<int?>("ProductInspection:MaxConcurrentAnalysis") ?? 5;
|
var maximum = Context.Configuration.GetValue<int?>("ProductInspection:MaxConcurrentAnalysis") ?? 5;
|
||||||
if (maximum is < 1 or > 100) throw new InvalidOperationException("识别并发数必须在 1 至 100 之间。");
|
if (maximum is < 1 or > 100) throw new InvalidOperationException("识别并发数必须在 1 至 100 之间。");
|
||||||
services.AddKeyedSingleton<SemaphoreSlim>("ProductInspectionAnalysisGate", (_, _) => new SemaphoreSlim(maximum, maximum));
|
services.AddKeyedSingleton<SemaphoreSlim>("ProductInspectionAnalysisGate", (_, _) => new SemaphoreSlim(maximum, maximum));
|
||||||
|
|||||||
@@ -86,6 +86,22 @@ namespace Store.Modules.CloudProduct.Controllers
|
|||||||
{
|
{
|
||||||
await _goodsIndexJob.ProcessPendingAsync();
|
await _goodsIndexJob.ProcessPendingAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>循环处理数据库中待分词的正常商品,成功写入索引后标记 is_segmented=1。</summary>
|
||||||
|
[HttpGet]
|
||||||
|
[EndpointSummary("重建所有待处理商品索引")]
|
||||||
|
public async Task<long> RebuildPendingIndex()
|
||||||
|
{
|
||||||
|
long count = 0;
|
||||||
|
int batchCount;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
batchCount = await _goodsService.IndexPendingGoodsAsync(1000);
|
||||||
|
count += batchCount;
|
||||||
|
} while (batchCount > 0);
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 分页搜索商品,可按标题、价格、类目、销量和平台筛选。
|
/// 分页搜索商品,可按标题、价格、类目、销量和平台筛选。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -112,9 +112,22 @@ public class GoodsViolationRepository(
|
|||||||
|
|
||||||
public async Task InsertLogsAsync(GoodsViolationLogEntity[] logs)
|
public async Task InsertLogsAsync(GoodsViolationLogEntity[] logs)
|
||||||
{
|
{
|
||||||
// 即使 ORM 拆分 INSERT,各批次也在同一事务内提交。
|
|
||||||
using var unit = Orm.CreateUnitOfWork();
|
using var unit = Orm.CreateUnitOfWork();
|
||||||
await unit.GetRepository<GoodsViolationLogEntity>().InsertAsync(logs);
|
unit.GetOrBeginTransaction();
|
||||||
|
foreach (var log in logs)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await unit.Orm.Insert(log).ExecuteAffrowsAsync();
|
||||||
|
}
|
||||||
|
catch (Exception ex) when (ex.GetBaseException() is MySql.Data.MySqlClient.MySqlException { Number: 1062 } duplicate
|
||||||
|
&& (duplicate.Message.EndsWith(".ux_violation_log_event'", StringComparison.Ordinal)
|
||||||
|
|| duplicate.Message.EndsWith("'ux_violation_log_event'", StringComparison.Ordinal)))
|
||||||
|
{
|
||||||
|
// 事件唯一键已存在即视为上报成功,保留首次记录,继续写入本批其他事件。
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
unit.Commit();
|
unit.Commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,5 @@
|
|||||||
"Model": "qwen3.7-flash",
|
"Model": "qwen3.7-flash",
|
||||||
"ApiKey": "sk-fa7fbaa3bb4047928f30bf05ff52c03a",
|
"ApiKey": "sk-fa7fbaa3bb4047928f30bf05ff52c03a",
|
||||||
"MaxConcurrentAnalysis": 5,
|
"MaxConcurrentAnalysis": 5,
|
||||||
"ConnectionString": "Server=192.168.0.200;Port=3306;Database=product_inspection;Uid=root;Pwd=123456;Allow User Variables=true"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ConnectionStrings": {
|
"ConnectionStrings": {
|
||||||
"DefaultConnection": "Server=192.168.0.200;Port=3306;Database=mysql;Uid=root;Pwd=123456;",
|
"DefaultConnection": "Max Pool Size=512;Database='kjd';Data Source='nj-cynosdbmysql-grp-hl51pkfr.sql.tencentcdb.com';Port=27660;User Id='kjd';Password='Temukjd0625';Charset=utf8mb4;"
|
||||||
},
|
},
|
||||||
// 登录认证:请求头使用 Authorization: Bearer <accessToken>。
|
// 登录认证:请求头使用 Authorization: Bearer <accessToken>。
|
||||||
"TokenAuth": {
|
"TokenAuth": {
|
||||||
|
|||||||
@@ -124,12 +124,16 @@ internal static class IntegrationChecks
|
|||||||
Check(!await db.Select<GoodsViolationLogEntity>().Where(x => x.GoodsId == first).AnyAsync(), "reporting alone creates no log");
|
Check(!await db.Select<GoodsViolationLogEntity>().Where(x => x.GoodsId == first).AnyAsync(), "reporting alone creates no log");
|
||||||
await violations.RecordLogsAsync([
|
await violations.RecordLogsAsync([
|
||||||
new() { ShopId = "shop-a", GoodsId = first, ReasonId = (int)existingReasonId, Action = ViolationLogAction.Report },
|
new() { ShopId = "shop-a", GoodsId = first, ReasonId = (int)existingReasonId, Action = ViolationLogAction.Report },
|
||||||
|
]);
|
||||||
|
await violations.RecordLogsAsync([
|
||||||
|
new() { ShopId = "shop-a", GoodsId = first, ReasonId = (int)existingReasonId, Action = ViolationLogAction.Report },
|
||||||
|
new() { ShopId = "shop-c", GoodsId = first, ReasonId = (int)ignoredReasonId, Action = ViolationLogAction.Report },
|
||||||
new() { ShopId = "shop-c", GoodsId = first, ReasonId = (int)ignoredReasonId, Action = ViolationLogAction.Report }
|
new() { ShopId = "shop-c", GoodsId = first, ReasonId = (int)ignoredReasonId, Action = ViolationLogAction.Report }
|
||||||
]);
|
]);
|
||||||
var reportLogs = await violations.GetLogsAsync(["shop-a", "shop-c"], first, 0, 50);
|
var reportLogs = await violations.GetLogsAsync(["shop-a", "shop-c"], first, 0, 50);
|
||||||
Check(reportLogs.Count == 2 && reportLogs.All(x => x.Action == ViolationLogAction.Report)
|
Check(reportLogs.Count == 2 && reportLogs.All(x => x.Action == ViolationLogAction.Report)
|
||||||
&& reportLogs.Any(x => x.ShopId == "shop-a" && x.ReasonId == existingReasonId)
|
&& reportLogs.Any(x => x.ShopId == "shop-a" && x.ReasonId == existingReasonId)
|
||||||
&& reportLogs.Any(x => x.ShopId == "shop-c" && x.ReasonId == ignoredReasonId), "keep report source and ignored reasons");
|
&& reportLogs.Any(x => x.ShopId == "shop-c" && x.ReasonId == ignoredReasonId), "skip existing and in-batch duplicate events while keeping new events and their sources");
|
||||||
foreach (var action in new[] { ViolationLogAction.AutoListingExcluded, ViolationLogAction.AutoOffShelf })
|
foreach (var action in new[] { ViolationLogAction.AutoListingExcluded, ViolationLogAction.AutoOffShelf })
|
||||||
await violations.RecordLogsAsync([new() { ShopId = "shop-b", GoodsId = first, ReasonId = (int)existingReasonId, Action = action }]);
|
await violations.RecordLogsAsync([new() { ShopId = "shop-b", GoodsId = first, ReasonId = (int)existingReasonId, Action = action }]);
|
||||||
var latest = (await violations.GetLogsAsync(["shop-b"], first, 0, 1)).Single();
|
var latest = (await violations.GetLogsAsync(["shop-b"], first, 0, 1)).Single();
|
||||||
|
|||||||
Reference in new issue
Block a user