feat: подробное отображение ошибок синхронизации
This commit is contained in:
@@ -23,7 +23,8 @@ public class ModeusApiClient : IModeusApiClient
|
||||
{
|
||||
var body = new { specialtyCode = request.SpecialtyCode, timeMin = request.TimeMin, timeMax = request.TimeMax, typeId = request.TypeId };
|
||||
var response = await _http.PostAsJsonAsync("/api/proxy/events/search", body);
|
||||
response.EnsureSuccessStatusCode();
|
||||
await EnsureSuccessAsync(response, "Modeus events search",
|
||||
$"specialtyCode={request.SpecialtyCode ?? "<empty>"}, timeMin={request.TimeMin:O}, timeMax={request.TimeMax:O}, typeId=[{string.Join(", ", request.TypeId ?? [])}]");
|
||||
return await response.Content.ReadFromJsonAsync<ModeusEventsResponse>() ?? new(new());
|
||||
}
|
||||
|
||||
@@ -46,7 +47,8 @@ public class ModeusApiClient : IModeusApiClient
|
||||
};
|
||||
|
||||
var response = await _http.PostAsJsonAsync("/api/proxy/rooms/search", body);
|
||||
response.EnsureSuccessStatusCode();
|
||||
await EnsureSuccessAsync(response, "Modeus rooms search",
|
||||
$"name=<empty>, sort=+building.name,+name, size={pageSize}, page={page}, deleted=false");
|
||||
|
||||
var payload = await response.Content.ReadFromJsonAsync<ModeusRoomsResponse>() ?? new ModeusRoomsResponse();
|
||||
allRooms.AddRange(payload.RoomItems);
|
||||
@@ -59,6 +61,20 @@ public class ModeusApiClient : IModeusApiClient
|
||||
return new ModeusRoomsResponse { Rooms = allRooms };
|
||||
}
|
||||
|
||||
private static async Task EnsureSuccessAsync(HttpResponseMessage response, string operation, string requestSummary)
|
||||
{
|
||||
if (response.IsSuccessStatusCode) return;
|
||||
|
||||
var responseBody = await response.Content.ReadAsStringAsync();
|
||||
if (responseBody.Length > 2000)
|
||||
responseBody = string.Concat(responseBody.AsSpan(0, 2000), "...<truncated>");
|
||||
|
||||
throw new HttpRequestException(
|
||||
$"{operation} failed with HTTP {(int)response.StatusCode} {response.ReasonPhrase}. Request: {requestSummary}. Response body: {responseBody}",
|
||||
null,
|
||||
response.StatusCode);
|
||||
}
|
||||
|
||||
public async Task<List<ModeusEmployee>> SearchEmployeeAsync(string fullname)
|
||||
{
|
||||
var response = await _http.GetFromJsonAsync<List<ModeusEmployee>>(
|
||||
|
||||
@@ -21,6 +21,7 @@ public class ScheduleSyncService : IScheduleSyncService
|
||||
|
||||
public async Task<SyncResultDto> SyncScheduleAsync(SyncScheduleRequest request)
|
||||
{
|
||||
const string stage = "schedule";
|
||||
int created = 0, updated = 0, skipped = 0;
|
||||
try
|
||||
{
|
||||
@@ -45,7 +46,18 @@ public class ScheduleSyncService : IScheduleSyncService
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Schedule sync failed");
|
||||
var result = new SyncResultDto(created, updated, skipped, ex.Message);
|
||||
var result = new SyncResultDto(created, updated, skipped, ex.Message, BuildErrorDetails(
|
||||
ex,
|
||||
stage,
|
||||
created,
|
||||
updated,
|
||||
skipped,
|
||||
[
|
||||
$"specialtyCode={request.SpecialtyCode ?? "<empty>"}",
|
||||
$"timeMin={request.TimeMin:O}",
|
||||
$"timeMax={request.TimeMax:O}",
|
||||
$"typeId=[{string.Join(", ", request.TypeId ?? [])}]"
|
||||
]));
|
||||
_lastStatus = new SyncStatusDto(DateTime.UtcNow, "failed", result);
|
||||
return result;
|
||||
}
|
||||
@@ -53,6 +65,7 @@ public class ScheduleSyncService : IScheduleSyncService
|
||||
|
||||
public async Task<SyncResultDto> SyncRoomsAsync()
|
||||
{
|
||||
const string stage = "rooms";
|
||||
int created = 0, updated = 0, skipped = 0;
|
||||
try
|
||||
{
|
||||
@@ -96,7 +109,13 @@ public class ScheduleSyncService : IScheduleSyncService
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Rooms sync failed");
|
||||
var result = new SyncResultDto(created, updated, skipped, ex.Message);
|
||||
var result = new SyncResultDto(created, updated, skipped, ex.Message, BuildErrorDetails(
|
||||
ex,
|
||||
stage,
|
||||
created,
|
||||
updated,
|
||||
skipped,
|
||||
["request=name:<empty>, sort:+building.name,+name, deleted:false, page size:100"]));
|
||||
_lastStatus = new SyncStatusDto(DateTime.UtcNow, "failed", result);
|
||||
return result;
|
||||
}
|
||||
@@ -109,4 +128,30 @@ public class ScheduleSyncService : IScheduleSyncService
|
||||
}
|
||||
|
||||
public Task<SyncStatusDto> GetLastSyncStatusAsync() => Task.FromResult(_lastStatus);
|
||||
|
||||
private static IReadOnlyList<string> BuildErrorDetails(
|
||||
Exception exception,
|
||||
string stage,
|
||||
int created,
|
||||
int updated,
|
||||
int skipped,
|
||||
IReadOnlyList<string> context)
|
||||
{
|
||||
var details = new List<string>
|
||||
{
|
||||
$"stage={stage}",
|
||||
$"exceptionType={exception.GetType().FullName}",
|
||||
$"message={exception.Message}",
|
||||
$"partialResult=created:{created}, updated:{updated}, skipped:{skipped}"
|
||||
};
|
||||
|
||||
if (exception is HttpRequestException httpException && httpException.StatusCode.HasValue)
|
||||
details.Add($"httpStatus={(int)httpException.StatusCode.Value} {httpException.StatusCode.Value}");
|
||||
|
||||
if (exception.InnerException != null)
|
||||
details.Add($"innerException={exception.InnerException.GetType().FullName}: {exception.InnerException.Message}");
|
||||
|
||||
details.AddRange(context);
|
||||
return details;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user