Add cancellation token support and extend timeout to 30 minutes for external API calls
All checks were successful
Build & Deploy Leave Service / build (push) Successful in 1m19s

This commit is contained in:
Suphonchai Phoonsawat 2026-01-30 13:35:58 +07:00
parent 0a170fd259
commit 659e06a08d
7 changed files with 76 additions and 76 deletions

View file

@ -53,15 +53,18 @@ namespace BMA.EHR.Application.Repositories
#region " For Call External API "
protected async Task<string> GetExternalAPIAsync(string apiPath, string accessToken, string apiKey)
protected async Task<string> GetExternalAPIAsync(string apiPath, string accessToken, string apiKey, CancellationToken cancellationToken = default)
{
try
{
// กำหนด timeout เป็น 30 นาที
using var timeoutCts = new CancellationTokenSource(TimeSpan.FromMinutes(30));
using var combinedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutCts.Token);
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken.Replace("Bearer ", ""));
client.DefaultRequestHeaders.Add("api-key", apiKey);
var _res = await client.GetAsync(apiPath);
var _res = await client.GetAsync(apiPath,cancellationToken: combinedCts.Token);
if (_res.IsSuccessStatusCode)
{
var _result = await _res.Content.ReadAsStringAsync();
@ -77,10 +80,13 @@ namespace BMA.EHR.Application.Repositories
}
}
protected async Task<string> SendExternalAPIAsync(HttpMethod method, string apiPath, string accessToken, object? body, string apiKey)
protected async Task<string> SendExternalAPIAsync(HttpMethod method, string apiPath, string accessToken, object? body, string apiKey, CancellationToken cancellationToken = default)
{
try
{
// กำหนด timeout เป็น 30 นาที
using var timeoutCts = new CancellationTokenSource(TimeSpan.FromMinutes(30));
using var combinedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutCts.Token);
// สร้าง request message
var request = new HttpRequestMessage(method, apiPath);
@ -92,7 +98,7 @@ namespace BMA.EHR.Application.Repositories
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken.Replace("Bearer ", ""));
client.DefaultRequestHeaders.Add("api-key", apiKey);
var _res = await client.SendAsync(request);
var _res = await client.SendAsync(request, combinedCts.Token);
if (_res.IsSuccessStatusCode)
{
var _result = await _res.Content.ReadAsStringAsync();
@ -109,11 +115,13 @@ namespace BMA.EHR.Application.Repositories
}
protected async Task<string> PostExternalAPIAsync(string apiPath, string accessToken, object? body, string apiKey)
protected async Task<string> PostExternalAPIAsync(string apiPath, string accessToken, object? body, string apiKey, CancellationToken cancellationToken = default)
{
try
{
// กำหนด timeout เป็น 30 นาที
using var timeoutCts = new CancellationTokenSource(TimeSpan.FromMinutes(30));
using var combinedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutCts.Token);
var json = JsonConvert.SerializeObject(body);
var stringContent = new StringContent(json, Encoding.UTF8, "application/json");
//stringContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
@ -122,7 +130,7 @@ namespace BMA.EHR.Application.Repositories
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken.Replace("Bearer ", ""));
client.DefaultRequestHeaders.Add("api-key", apiKey);
var _res = await client.PostAsync(apiPath, stringContent);
var _res = await client.PostAsync(apiPath, stringContent, combinedCts.Token);
if (_res.IsSuccessStatusCode)
{
var _result = await _res.Content.ReadAsStringAsync();
@ -138,10 +146,13 @@ namespace BMA.EHR.Application.Repositories
}
}
protected async Task<bool> PostExternalAPIBooleanAsync(string apiPath, string accessToken, object? body, string apiKey)
protected async Task<bool> PostExternalAPIBooleanAsync(string apiPath, string accessToken, object? body, string apiKey, CancellationToken cancellationToken = default)
{
try
{
// กำหนด timeout เป็น 30 นาที
using var timeoutCts = new CancellationTokenSource(TimeSpan.FromMinutes(30));
using var combinedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutCts.Token);
var json = JsonConvert.SerializeObject(body);
var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json");
stringContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
@ -150,7 +161,7 @@ namespace BMA.EHR.Application.Repositories
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken.Replace("Bearer ", ""));
client.DefaultRequestHeaders.Add("api-key", apiKey);
var _res = await client.PostAsync(apiPath, stringContent);
var _res = await client.PostAsync(apiPath, stringContent, combinedCts.Token);
return _res.IsSuccessStatusCode;
}
}

View file

@ -61,9 +61,12 @@ namespace BMA.EHR.Application.Repositories.Leaves.TimeAttendants
return await _dbContext.Set<DutyTime>().Where(x => x.IsActive).ToListAsync();
}
public async Task<DutyTime?> GetDefaultAsync()
public async Task<DutyTime?> GetDefaultAsync(CancellationToken cancellationToken = default)
{
return await _dbContext.Set<DutyTime>().Where(x => x.IsDefault).FirstOrDefaultAsync();
// กำหนด timeout เป็น 30 นาที
using var timeoutCts = new CancellationTokenSource(TimeSpan.FromMinutes(30));
using var combinedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutCts.Token);
return await _dbContext.Set<DutyTime>().Where(x => x.IsDefault).FirstOrDefaultAsync(combinedCts.Token);
}
#endregion

View file

@ -101,14 +101,17 @@ namespace BMA.EHR.Application.Repositories.Leaves.TimeAttendants
return data;
}
public async Task<UserDutyTime?> GetLastEffectRound(Guid profileId, DateTime? effectiveDate = null)
public async Task<UserDutyTime?> GetLastEffectRound(Guid profileId, DateTime? effectiveDate = null, CancellationToken cancellationToken = default)
{
// กำหนด timeout เป็น 30 นาที
using var timeoutCts = new CancellationTokenSource(TimeSpan.FromMinutes(30));
using var combinedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutCts.Token);
effectiveDate ??= DateTime.Now;
var data = await _dbContext.Set<UserDutyTime>()
.Where(x => x.ProfileId == profileId)
.Where(x => x.EffectiveDate.Value.Date <= effectiveDate.Value.Date)
.OrderByDescending(x => x.EffectiveDate)
.FirstOrDefaultAsync();
.FirstOrDefaultAsync(combinedCts.Token);
return data;
}

View file

@ -74,12 +74,16 @@ namespace BMA.EHR.Application.Repositories.Leaves.TimeAttendants
return data;
}
public async Task<UserTimeStamp?> GetLastRecord(Guid keycloakId)
public async Task<UserTimeStamp?> GetLastRecord(Guid keycloakId, CancellationToken cancellationToken = default)
{
// กำหนด timeout เป็น 30 นาที
using var timeoutCts = new CancellationTokenSource(TimeSpan.FromMinutes(30));
using var combinedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutCts.Token);
var data = await _dbContext.Set<UserTimeStamp>()
.Where(u => u.KeycloakUserId == keycloakId)
.OrderByDescending(u => u.CheckIn)
.FirstOrDefaultAsync();
.FirstOrDefaultAsync(combinedCts.Token);
return data;
}

View file

@ -186,14 +186,14 @@ namespace BMA.EHR.Application.Repositories
}
}
public async Task<GetProfileByKeycloakIdDto?> GetProfileByKeycloakIdNewAsync(Guid keycloakId, string? accessToken)
public async Task<GetProfileByKeycloakIdDto?> GetProfileByKeycloakIdNewAsync(Guid keycloakId, string? accessToken,CancellationToken cancellationToken = default)
{
try
{
var apiPath = $"{_configuration["API"]}/org/dotnet/by-keycloak/{keycloakId}";
var apiKey = _configuration["API_KEY"];
var apiResult = await GetExternalAPIAsync(apiPath, accessToken ?? "", apiKey);
var apiResult = await GetExternalAPIAsync(apiPath, accessToken ?? "", apiKey, cancellationToken);
if (apiResult != null)
{
var raw = JsonConvert.DeserializeObject<GetProfileByKeycloakIdResultDto>(apiResult);