From a39856db9c84652f11a997a5ed28c568aaed3ff4 Mon Sep 17 00:00:00 2001
From: xiaolipro <2357729423@qq.com>
Date: Fri, 11 Sep 2026 15:44:05 +0800
Subject: [PATCH] =?UTF-8?q?feat:=20=E4=BC=98=E5=8C=96es=20idx=20404?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/TrackCenter.Repository/ES/EsExtensions.cs | 70 +++++++++++++++-
.../Repositories/TrackDetailsEsRepository.cs | 81 ++++++++++++++-----
2 files changed, 129 insertions(+), 22 deletions(-)
diff --git a/src/TrackCenter.Repository/ES/EsExtensions.cs b/src/TrackCenter.Repository/ES/EsExtensions.cs
index cbc9bf06..2b0e1578 100644
--- a/src/TrackCenter.Repository/ES/EsExtensions.cs
+++ b/src/TrackCenter.Repository/ES/EsExtensions.cs
@@ -1,5 +1,5 @@
-using TrackCenter.Repository.ES;
using Nest;
+using TrackCenter.Domain.Consts;
using TrackCenter.Domain.SeedWork;
namespace TrackCenter.Repository.ES;
@@ -9,12 +9,74 @@ namespace TrackCenter.Repository.ES;
///
public static class EsExtensions
{
+ ///
+ /// 轨迹明细实际写入月度索引 track_details-yyyy.MM;读请求走通配符,
+ /// 无匹配索引时返回空结果(首次部署 / 尚未 Migrate 别名)。
+ ///
+ public static SearchDescriptor UseTrackDetailsIndex(this SearchDescriptor descriptor) where T : class
+ {
+ return descriptor
+ .Index($"{GlobalConst.TrackDetailsIndex}-*")
+ .IgnoreUnavailable()
+ .AllowNoIndices();
+ }
+
+ ///
+ /// 轨迹明细按查询更新:目标索引不存在时视为无匹配文档。
+ ///
+ public static UpdateByQueryDescriptor UseTrackDetailsIndex(this UpdateByQueryDescriptor descriptor)
+ where T : class
+ {
+ return descriptor
+ .Index($"{GlobalConst.TrackDetailsIndex}-*")
+ .IgnoreUnavailable()
+ .AllowNoIndices();
+ }
+
+ public static DeleteByQueryDescriptor UseTrackDetailsIndex(this DeleteByQueryDescriptor descriptor)
+ where T : class
+ {
+ return descriptor
+ .Index($"{GlobalConst.TrackDetailsIndex}-*")
+ .IgnoreUnavailable()
+ .AllowNoIndices();
+ }
+
+ ///
+ /// 索引/别名不存在(含 NEST 对 404 的包装错误)。
+ ///
+ public static bool IsIndexUnavailable(this IResponse response)
+ {
+ if (response.IsValid)
+ return false;
+
+ if (response.ApiCall?.HttpStatusCode == 404)
+ return true;
+
+ if (IsIndexNotFoundType(response.ServerError?.Error?.Type)
+ || IsIndexNotFoundType(response.ServerError?.Error?.CausedBy?.Type))
+ return true;
+
+ var rootCauses = response.ServerError?.Error?.RootCause;
+ if (rootCauses != null && rootCauses.Any(x => IsIndexNotFoundType(x.Type)))
+ return true;
+
+ // NEST: Invalid NEST response built from a successful (404) low level call on POST: /track_details/_search
+ var debug = response.DebugInformation;
+ if (!string.IsNullOrEmpty(debug)
+ && (debug.Contains("index_not_found_exception", StringComparison.OrdinalIgnoreCase)
+ || debug.Contains("successful (404)", StringComparison.OrdinalIgnoreCase)))
+ return true;
+
+ return false;
+ }
+
+ private static bool IsIndexNotFoundType(string? type) =>
+ string.Equals(type, "index_not_found_exception", StringComparison.OrdinalIgnoreCase);
+
///
/// return list with id
///
- ///
- ///
- ///
public static List ToIdList(this ISearchResponse response) where T : IdBaseIndex
{
var dtos = new List();
diff --git a/src/TrackCenter.Repository/Repositories/TrackDetailsEsRepository.cs b/src/TrackCenter.Repository/Repositories/TrackDetailsEsRepository.cs
index e1582145..6402cc23 100644
--- a/src/TrackCenter.Repository/Repositories/TrackDetailsEsRepository.cs
+++ b/src/TrackCenter.Repository/Repositories/TrackDetailsEsRepository.cs
@@ -25,7 +25,7 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract(s => s
- .Index(GlobalConst.TrackDetailsIndex)
+ .UseTrackDetailsIndex()
.Source()
.Version()
.Size(SafelyLimit)
@@ -39,7 +39,7 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract(s => s
- .Index(GlobalConst.TrackDetailsIndex)
+ .UseTrackDetailsIndex()
.Version()
.Source(s2 => s2.Includes(fd => fd
.Field(f => f.IndexName)
@@ -60,6 +60,9 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract();
+
throw new InvalidOperationException(
$"轨迹查询失败,orderIds:[{orderIds.JoinAsString(", ")}],trackCode:{trackCode},原因:{r.DebugInformation}。");
}
@@ -126,7 +129,7 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract(x => x
- .Index(GlobalConst.TrackDetailsIndex)
+ .UseTrackDetailsIndex()
.Version()
.Query(q => q.Bool(b => b
.Should(musts)
@@ -137,7 +140,7 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract(x => x
- .Index(GlobalConst.TrackDetailsIndex)
+ .UseTrackDetailsIndex()
.Version()
.Query(q => q.Bool(b => b
.Must(musts)
@@ -148,6 +151,9 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract>();
+
throw new InvalidOperationException($"运输预警明细查询失败,原因:{r.DebugInformation}。");
}
@@ -159,7 +165,7 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract>> GetTrackStatusEarliestDictAsync(HashSet orderIds)
{
var response = await Context.SearchAsync(s => s
- .Index(GlobalConst.TrackDetailsIndex)
+ .UseTrackDetailsIndex()
.Size(0) // 不需要实际文档,只需要聚合结果
.Query(q => q
.Terms(t => t
@@ -191,6 +197,9 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract>();
+
throw new InvalidOperationException(
$"最新轨迹查询失败,orderIds:[{orderIds.JoinAsString(", ")}],原因:{response.DebugInformation}。");
}
@@ -226,7 +235,7 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract> GetLatestDictAsync(HashSet orderIds)
{
var r = await Context.SearchAsync(s => s
- .Index(GlobalConst.TrackDetailsIndex)
+ .UseTrackDetailsIndex()
.Size(0) // 不需要实际文档,只需要聚合结果
.Query(q => q
.Terms(t => t
@@ -253,6 +262,9 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract();
+
throw new InvalidOperationException(
$"最新轨迹查询失败,orderIds:[{orderIds.JoinAsString(", ")}],原因:{r.DebugInformation}。");
}
@@ -281,7 +293,7 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract(x => x
- .Index(GlobalConst.TrackDetailsIndex)
+ .UseTrackDetailsIndex()
.Source(s => s.Includes(fd => fd
.Field(f => f.TrackEnContent)
.Field(f => f.TrackContent)
@@ -335,6 +347,9 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract();
+
throw new InvalidOperationException(
$"最新轨迹查询失败,orderIds:[{orderIds.JoinAsString(", ")}],trackCodes:[{trackCodes.JoinAsString(", ")}],原因:{r.DebugInformation}。");
}
@@ -345,7 +360,7 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract AnyAsync(int orderId, string originTrackDataHash)
{
var r = await Context.SearchAsync(x => x
- .Index(GlobalConst.TrackDetailsIndex)
+ .UseTrackDetailsIndex()
.Source(s => s.Includes(fd => fd.Field(f => f.TrackCode)))
.Query(q =>
q.Term(f => f.OrderId, orderId)
@@ -355,6 +370,9 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract(u => u
- .Index(GlobalConst.TrackDetailsIndex)
+ .UseTrackDetailsIndex()
.Query(q => q
.Ids(t => t.Values(indexes.Select(x => x.Id)))
)
@@ -465,7 +483,7 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract Context.BulkAsync(desc),
successValidator: response =>
{
- if (response.IsValid) // 认为成功
+ if (response.IsValid || response.IsIndexUnavailable()) // 认为成功或索引不存在
return true;
if (response.ServerError.Status == 409) //版本冲突认为失败,则重试
@@ -620,7 +638,7 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract(x => x
- .Index(GlobalConst.TrackDetailsIndex)
+ .UseTrackDetailsIndex()
.Source()
.Version()
.Query(q =>
@@ -637,6 +655,9 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract();
+
throw new InvalidOperationException(
$"轨迹查询失败,orderType:{orderType},orderNos:{orderNos},原因:{r.DebugInformation}。");
}
@@ -647,7 +668,7 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract> GetListAsync(int orderId)
{
var r = await Context.SearchAsync(x => x
- .Index(GlobalConst.TrackDetailsIndex)
+ .UseTrackDetailsIndex()
.Version()
.Query(q =>
q.Term(t => t.OrderId, orderId)
@@ -660,6 +681,9 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract();
+
throw new InvalidOperationException($"轨迹查询失败,orderId:{orderId},原因:{r.DebugInformation}。");
}
@@ -686,7 +710,7 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract(x => x
- .Index(GlobalConst.TrackDetailsIndex)
+ .UseTrackDetailsIndex()
.Version()
.Query(_ => query)
.Size(SafelyLimit)
@@ -697,6 +721,9 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract();
+
throw new InvalidOperationException($"轨迹查询失败,orderIds:[{string.Join(',', orderIds)}],原因:{r.DebugInformation}。");
}
@@ -720,7 +747,7 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract(x => x
- .Index(GlobalConst.TrackDetailsIndex)
+ .UseTrackDetailsIndex()
.Version()
.Source(s => s.Includes(fd => fd
.Field(f => f.IndexName)
@@ -736,6 +763,9 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract();
+
throw new InvalidOperationException(
$"轨迹查询失败,orderIds:[{orderIds.JoinAsString(", ")}],trackCodes:[{trackCodes.JoinAsString(", ")}],原因:{search.DebugInformation}。");
}
@@ -774,12 +804,15 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract esIds)
{
var r = await Context.DeleteByQueryAsync(x => x
- .Index(GlobalConst.TrackDetailsIndex)
+ .UseTrackDetailsIndex()
.Query(q => q.Ids(i => i.Values(esIds)))
);
if (!r.IsValid)
{
+ if (r.IsIndexUnavailable())
+ return;
+
throw new InvalidOperationException($"轨迹删除失败,ids:[{string.Join(", ", esIds)}],原因:{r.DebugInformation}。");
}
}
@@ -787,7 +820,7 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract> GetDataByIds(string[] ids)
{
var r = await Context.SearchAsync(m => m
- .Index(GlobalConst.TrackDetailsIndex)
+ .UseTrackDetailsIndex()
.Version()
.Query(
q => q.Ids(i => i.Values(ids))
@@ -795,6 +828,9 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract();
+
throw new InvalidOperationException($"轨迹查询失败,ids:[{string.Join(", ", ids)}],原因:{r.DebugInformation}。");
}
@@ -804,7 +840,7 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract GetDetailAsync(string orderNo, string trackCode, TrackOrderType orderType, string appKey, DateTime trackTime)
{
var res = await Context.SearchAsync(s => s
- .Index(GlobalConst.TrackDetailsIndex)
+ .UseTrackDetailsIndex()
.Query(q => q
.Bool(b => b
.Must(mu => mu
@@ -832,6 +868,15 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract