add Background Task
This commit is contained in:
parent
75ddebba37
commit
3ae9be5869
6 changed files with 211 additions and 2 deletions
|
|
@ -41,6 +41,7 @@
|
|||
<PackageReference Include="Serilog.Exceptions" Version="8.4.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Debug" Version="2.0.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Elasticsearch" Version="9.0.3" />
|
||||
<PackageReference Include="SocketIoClientDotNet" Version="0.9.13" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore.Annotations" Version="6.5.0" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
|
||||
</ItemGroup>
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@ using BMA.EHR.Domain.ModelsExam.Candidate;
|
|||
using BMA.EHR.Domain.Shared;
|
||||
using BMA.EHR.Infrastructure.Persistence;
|
||||
using BMA.EHR.Insignia.Service.Requests;
|
||||
using BMA.EHR.Insignia.Service.Services;
|
||||
using Hangfire.Processing;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
|
@ -51,6 +53,8 @@ namespace BMA.EHR.Insignia.Service.Controllers
|
|||
private readonly IConfiguration _configuration;
|
||||
private readonly PermissionRepository _permission;
|
||||
|
||||
private readonly IBackgroundTaskQueue _queue;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
|
|
@ -73,7 +77,8 @@ namespace BMA.EHR.Insignia.Service.Controllers
|
|||
InsigniaPeriodsRepository insigniaPeriodRepository,
|
||||
InsigniaReportRepository insigniaReportRepository,
|
||||
IConfiguration configuration,
|
||||
PermissionRepository permission)
|
||||
PermissionRepository permission,
|
||||
IBackgroundTaskQueue queue)
|
||||
{
|
||||
_context = context;
|
||||
_documentService = documentService;
|
||||
|
|
@ -86,6 +91,8 @@ namespace BMA.EHR.Insignia.Service.Controllers
|
|||
_configuration = configuration;
|
||||
_permission = permission;
|
||||
_insigniaReportRepository = insigniaReportRepository;
|
||||
|
||||
_queue = queue;
|
||||
}
|
||||
|
||||
#region " Properties "
|
||||
|
|
@ -626,6 +633,17 @@ namespace BMA.EHR.Insignia.Service.Controllers
|
|||
return Success();
|
||||
}
|
||||
|
||||
[HttpGet("bg/{type}/{insigniaPeriodId:length(36)}")]
|
||||
public async Task<ActionResult<ResponseObject>> BackgroundCalculateInsigniaRequestByTypeAsync(string type, Guid insigniaPeriodId)
|
||||
{
|
||||
await _queue.QueueBackgroundWorkItemAsync(async token =>
|
||||
{
|
||||
// Logic งาน background จริงเช่น:
|
||||
//await LongRunningProcess(jobInfo, token);
|
||||
});
|
||||
return Success("Background job started.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// คำนวณราชชื่อผู้ได้รับเครื่องราช (แยกตาม officer, employee)
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ using BMA.EHR.Infrastructure;
|
|||
using BMA.EHR.Infrastructure.Persistence;
|
||||
using BMA.EHR.Insignia.Service;
|
||||
using BMA.EHR.Insignia.Service.Filters;
|
||||
using BMA.EHR.Insignia.Service.Services;
|
||||
using Hangfire;
|
||||
using Hangfire.Common;
|
||||
using Hangfire.MySql;
|
||||
|
|
@ -26,7 +27,6 @@ var builder = WebApplication.CreateBuilder(args);
|
|||
var issuer = builder.Configuration["Jwt:Issuer"];
|
||||
var key = builder.Configuration["Jwt:Key"];
|
||||
|
||||
|
||||
IdentityModelEventSource.ShowPII = true;
|
||||
|
||||
builder.Services.AddHttpContextAccessor();
|
||||
|
|
@ -88,6 +88,9 @@ var builder = WebApplication.CreateBuilder(args);
|
|||
builder.Services.AddLeaveApplication();
|
||||
builder.Services.AddLeavePersistence(builder.Configuration);
|
||||
|
||||
builder.Services.AddSingleton<IBackgroundTaskQueue, BackgroundTaskQueue>();
|
||||
builder.Services.AddHostedService<InsigniaRequestProcessService>();
|
||||
|
||||
|
||||
|
||||
builder.Services.AddControllers(options =>
|
||||
|
|
|
|||
26
BMA.EHR.Insignia/Services/BackgroundTaskQueue.cs
Normal file
26
BMA.EHR.Insignia/Services/BackgroundTaskQueue.cs
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
using System.Collections.Concurrent;
|
||||
|
||||
namespace BMA.EHR.Insignia.Service.Services
|
||||
{
|
||||
public class BackgroundTaskQueue : IBackgroundTaskQueue
|
||||
{
|
||||
private readonly ConcurrentQueue<Func<CancellationToken, ValueTask>> _workItems = new();
|
||||
private readonly SemaphoreSlim _signal = new(0);
|
||||
|
||||
public ValueTask QueueBackgroundWorkItemAsync(Func<CancellationToken, ValueTask> workItem)
|
||||
{
|
||||
if (workItem == null)
|
||||
throw new ArgumentNullException(nameof(workItem));
|
||||
_workItems.Enqueue(workItem);
|
||||
_signal.Release();
|
||||
return ValueTask.CompletedTask;
|
||||
}
|
||||
|
||||
public async ValueTask<Func<CancellationToken, ValueTask>> DequeueAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
await _signal.WaitAsync(cancellationToken);
|
||||
_workItems.TryDequeue(out var workItem);
|
||||
return workItem!;
|
||||
}
|
||||
}
|
||||
}
|
||||
8
BMA.EHR.Insignia/Services/IBackgroundTaskQueue.cs
Normal file
8
BMA.EHR.Insignia/Services/IBackgroundTaskQueue.cs
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
namespace BMA.EHR.Insignia.Service.Services
|
||||
{
|
||||
public interface IBackgroundTaskQueue
|
||||
{
|
||||
ValueTask QueueBackgroundWorkItemAsync(Func<CancellationToken, ValueTask> workItem);
|
||||
ValueTask<Func<CancellationToken, ValueTask>> DequeueAsync(CancellationToken cancellationToken);
|
||||
}
|
||||
}
|
||||
153
BMA.EHR.Insignia/Services/InsigniaRequestProcessService.cs
Normal file
153
BMA.EHR.Insignia/Services/InsigniaRequestProcessService.cs
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
using Microsoft.Extensions.Hosting;
|
||||
using Quobject.SocketIoClientDotNet.Client;
|
||||
using Sentry;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System;
|
||||
|
||||
namespace BMA.EHR.Insignia.Service.Services;
|
||||
|
||||
public class InsigniaRequestProcessService : BackgroundService
|
||||
{
|
||||
private readonly IBackgroundTaskQueue _queue;
|
||||
private Socket _socket;
|
||||
private bool _isConnected = false;
|
||||
|
||||
public InsigniaRequestProcessService(IBackgroundTaskQueue queue)
|
||||
{
|
||||
_queue = queue;
|
||||
}
|
||||
|
||||
public override Task StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
_socket = IO.Socket("https://bma-ehr.frappet.synology.me", new IO.Options
|
||||
{
|
||||
Path = "/api/v1/org-socket",
|
||||
//Query = new Dictionary<string, string>
|
||||
//{
|
||||
// { "EIO", "4" },
|
||||
// { "transport", "polling" },
|
||||
// { "t", "tkitfptn" }
|
||||
//}
|
||||
});
|
||||
|
||||
_socket.On(Socket.EVENT_CONNECT, () =>
|
||||
{
|
||||
_isConnected = true;
|
||||
Console.WriteLine("Connected to WebSocket server at: https://bma-ehr.frappet.synology.me/api/v1/org-socket");
|
||||
});
|
||||
|
||||
_socket.On(Socket.EVENT_DISCONNECT, () =>
|
||||
{
|
||||
_isConnected = false;
|
||||
Console.WriteLine("Disconnected from WebSocket server");
|
||||
});
|
||||
|
||||
_socket.On(Socket.EVENT_ERROR, (data) =>
|
||||
{
|
||||
_isConnected = false;
|
||||
Console.WriteLine($"WebSocket error: {data}");
|
||||
});
|
||||
|
||||
_socket.Connect();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_isConnected = false;
|
||||
Console.WriteLine($"Failed to initialize WebSocket connection: {ex.Message}");
|
||||
}
|
||||
|
||||
return base.StartAsync(cancellationToken);
|
||||
}
|
||||
|
||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||
{
|
||||
var userId = "4064c2b2-0414-464a-97c6-4a47c325b9a3";
|
||||
|
||||
while (!stoppingToken.IsCancellationRequested)
|
||||
{
|
||||
try
|
||||
{
|
||||
var workItem = await _queue.DequeueAsync(stoppingToken);
|
||||
if (workItem != null)
|
||||
{
|
||||
Console.WriteLine($"Starting background task at: {DateTime.Now}");
|
||||
await workItem(stoppingToken);
|
||||
Console.WriteLine($"Finished background task at: {DateTime.Now}");
|
||||
|
||||
// Send notification to WebSocket after task completion
|
||||
if (_socket != null && _isConnected)
|
||||
{
|
||||
_socket.Emit("send-command-notification",
|
||||
new
|
||||
{
|
||||
success = true,
|
||||
message = "Background Task Completed Successfully",
|
||||
payload = new {
|
||||
completedAt = DateTime.Now,
|
||||
taskType = "background_processing"
|
||||
}
|
||||
},
|
||||
new
|
||||
{
|
||||
userId = userId
|
||||
});
|
||||
|
||||
Console.WriteLine("WebSocket notification sent successfully");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("WebSocket is not connected. Unable to send notification.");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Error processing background task: {ex.Message}");
|
||||
|
||||
// Send error notification to WebSocket
|
||||
if (_socket != null && _isConnected)
|
||||
{
|
||||
_socket.Emit("send-command-notification",
|
||||
new
|
||||
{
|
||||
success = false,
|
||||
message = "Background Task Failed",
|
||||
payload = new {
|
||||
error = ex.Message,
|
||||
failedAt = DateTime.Now,
|
||||
taskType = "background_processing"
|
||||
}
|
||||
},
|
||||
new
|
||||
{
|
||||
userId = userId
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override Task StopAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_socket != null)
|
||||
{
|
||||
Console.WriteLine("Disconnecting from WebSocket server...");
|
||||
_socket.Disconnect();
|
||||
_isConnected = false;
|
||||
_socket = null;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Error disconnecting WebSocket: {ex.Message}");
|
||||
}
|
||||
|
||||
return base.StopAsync(cancellationToken);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue