From a173a7dc3c34deae5b28ceb18418e60f4a352baf Mon Sep 17 00:00:00 2001 From: Suphonchai Phoonsawat Date: Wed, 29 Apr 2026 09:57:26 +0700 Subject: [PATCH] fix CheckInConsumer Memery Falult --- BMA.EHR.CheckInConsumer/Dockerfile | 22 ++++++ BMA.EHR.CheckInConsumer/Program.cs | 111 ++++++++++++++--------------- 2 files changed, 74 insertions(+), 59 deletions(-) diff --git a/BMA.EHR.CheckInConsumer/Dockerfile b/BMA.EHR.CheckInConsumer/Dockerfile index 1c90d6f2..93046386 100644 --- a/BMA.EHR.CheckInConsumer/Dockerfile +++ b/BMA.EHR.CheckInConsumer/Dockerfile @@ -48,6 +48,28 @@ RUN dotnet build -c Release -o /app/build # ใช้ stage ใหม่สำหรับการ runtime FROM mcr.microsoft.com/dotnet/runtime:8.0 AS runtime +# GC Configuration เพื่อป้องกัน Segmentation Fault +# ใช้ Server GC สำหรับ performance ที่ดีขึ้น +ENV DOTNET_SERVER_GARBAGECOLLECTION=true +# ตั้งค่า GC mode เป็น Server +ENV DOTNET_GCServer=true +# จำกัดจำนวน GC heap (ป้องกัน memory fragmentation) +ENV DOTNET_GCHeapCount=16 +# เปิดใช้ GC hard limit ป้องกัน memory over-commit +ENV DOTNET_GCHeapHardLimit=268435456 +# ตั้งค่า GC latency mode เป็น LowLatency (ลดเวลาที่ GC block threads) +ENV DOTNET_GCLatencyMode=0 +# เพิ่มขนาด LOH (Large Object Heap) เพื่อลดการ realloc +ENV DOTNET_GCLargeObjectHeapCompactionMode=2 +# ตั้งค่า ThreadPool Min Threads เพื่อป้องกัน thread starvation +ENV DOTNET_TP_MinThreads=10 +ENV DOTNET_TP_MaxThreads=100 +# ป้องกัน hang จาก HTTP requests +ENV DOTNET_HTTP_SOCKETS_BUFFER_SIZE=65536 +# เพิ่ม stack size เพื่อป้องกัน stack overflow +ENV DOTNET_ThreadPool_LowWaterMark=10 +ENV DOTNET_ThreadPool_HighWaterMark=100 + # กำหนด working directory สำหรับ runtime WORKDIR /app diff --git a/BMA.EHR.CheckInConsumer/Program.cs b/BMA.EHR.CheckInConsumer/Program.cs index 0ae439cf..b2fa41f3 100644 --- a/BMA.EHR.CheckInConsumer/Program.cs +++ b/BMA.EHR.CheckInConsumer/Program.cs @@ -1,4 +1,4 @@ -using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Configuration; using RabbitMQ.Client; using RabbitMQ.Client.Events; using System.Text; @@ -21,77 +21,84 @@ var queue = configuration["Rabbit:Queue"] ?? "basic-queue"; // create connection var factory = new ConnectionFactory() { - //Uri = new Uri("amqp://admin:P@ssw0rd@192.168.4.11:5672") - HostName = host,// หรือ hostname ของ RabbitMQ Server ที่คุณใช้ - UserName = user, // ใส่ชื่อผู้ใช้ของคุณ - Password = pass // ใส่รหัสผ่านของคุณ + HostName = host, + UserName = user, + Password = pass, + DispatchConsumersAsync = true }; using var connection = factory.CreateConnection(); using var channel = connection.CreateModel(); -//channel.QueueDeclare(queue: "bma-checkin-queue", durable: true, exclusive: false, autoDelete: false, arguments: null); channel.QueueDeclare(queue: queue, durable: true, exclusive: false, autoDelete: false, arguments: null); +// Create a SINGLE static HttpClient instance to prevent socket exhaustion +using var httpClient = new HttpClient(); +httpClient.Timeout = TimeSpan.FromSeconds(300); // 5 นาที + var consumer = new EventingBasicConsumer(channel); consumer.Received += async (model, ea) => { - var body = ea.Body.ToArray(); - var message = Encoding.UTF8.GetString(body); - await CallRestApi(message); + try + { + var body = ea.Body.ToArray(); + var message = Encoding.UTF8.GetString(body); - // convert string into object - //var request = JsonConvert.DeserializeObject(message); - //using (var db = new ApplicationDbContext()) - //{ - // var item = new AttendantItem - // { - // Name = request.Name, - // CheckInDateTime = request.CheckInDateTime, - // }; - // db.AttendantItems.Add(item); - // db.SaveChanges(); + //WriteToConsole($"ได้รับคำขอจาก Queue: {message}"); - // WriteToConsole($"ได้รับคำขอจาก Queue: {message}"); - // WriteToConsole($"ตอบกลับจาก REST API: {JsonConvert.SerializeObject(item)}"); - //} - - WriteToConsole($"ได้รับคำขอจาก Queue: {message}"); - //WriteToConsole($"ตอบกลับจาก REST API: {JsonConvert.SerializeObject(item)}"); + await CallRestApi(message, httpClient, configuration); + } + catch (Exception ex) + { + WriteToConsole($"Error processing message: {ex.Message}"); + } }; -//channel.BasicConsume(queue: "bma-checkin-queue", autoAck: true, consumer: consumer); channel.BasicConsume(queue: queue, autoAck: true, consumer: consumer); -//Console.WriteLine("\nPress 'Enter' to exit the process..."); +WriteToConsole("Consumer started. Waiting for messages..."); +// Keep the application running await Task.Delay(-1); static void WriteToConsole(string message) { - Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} : {message}"); + Console.WriteLine($"{DateTime.Now:yyyy-MM-dd HH:mm:ss} : {message}"); } -async Task CallRestApi(string requestData) +static async Task CallRestApi(string requestData, HttpClient client, IConfiguration configuration) { - using var client = new HttpClient(); - var apiPath = $"{configuration["API"]}/leave/process-check-in"; - - var content = new StringContent(requestData, Encoding.UTF8, "application/json"); - - var response = await client.PostAsync(apiPath, content); - - if (response.IsSuccessStatusCode) + try { - var responseContent = await response.Content.ReadAsStringAsync(); - WriteToConsole(responseContent); + var apiPath = $"{configuration["API"]}/leave/process-check-in"; + var content = new StringContent(requestData, Encoding.UTF8, "application/json"); + + var response = await client.PostAsync(apiPath, content); + + if (response.IsSuccessStatusCode) + { + var responseContent = await response.Content.ReadAsStringAsync(); + //WriteToConsole($"Success: {responseContent}"); + } + else + { + var errorMessage = await response.Content.ReadAsStringAsync(); + var res = JsonSerializer.Deserialize(errorMessage); + WriteToConsole($"API Error: {res?.Message ?? "Unknown error"}"); + } } - else + catch (HttpRequestException ex) { - var errorMessage = await response.Content.ReadAsStringAsync(); - var res = JsonSerializer.Deserialize(errorMessage); - WriteToConsole($"Error: {res.Message}"); + WriteToConsole($"HTTP Error: {ex.Message}"); + } + catch (TaskCanceledException ex) + { + WriteToConsole($"Timeout: {ex.Message}"); + } + catch (Exception ex) + { + WriteToConsole($"Unexpected Error: {ex.Message}"); } } @@ -110,28 +117,14 @@ public class ResponseObject public class CheckTimeDtoRB { public Guid? CheckInId { get; set; } - - public double Lat { get; set; } = 0; - - public double Lon { get; set; } = 0; - - public string POI { get; set; } = string.Empty; - - public bool IsLocation { get; set; } = true; - public string? LocationName { get; set; } = string.Empty; - public string? Remark { get; set; } = string.Empty; - public Guid? UserId { get; set; } - public DateTime? CurrentDate { get; set; } - public string? CheckInFileName { get; set; } - public byte[]? CheckInFileBytes { get; set; } -} \ No newline at end of file +}