leave report
This commit is contained in:
parent
3ae9be5869
commit
8001dd0c11
12 changed files with 678 additions and 244 deletions
|
|
@ -1,4 +1,4 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
|
|
@ -41,7 +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="SocketIOClient" Version="3.0.8" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore.Annotations" Version="6.5.0" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
|
||||
</ItemGroup>
|
||||
|
|
|
|||
16
BMA.EHR.Insignia/Configuration/WebSocketConfiguration.cs
Normal file
16
BMA.EHR.Insignia/Configuration/WebSocketConfiguration.cs
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
namespace BMA.EHR.Insignia.Service.Configuration
|
||||
{
|
||||
public class WebSocketConfiguration
|
||||
{
|
||||
public const string SectionName = "WebSocket";
|
||||
|
||||
public string Url { get; set; } = "https://bma-ehr.frappet.synology.me";
|
||||
public string Path { get; set; } = "/api/v1/org-socket";
|
||||
public string DefaultUserId { get; set; } = "4064c2b2-0414-464a-97c6-4a47c325b9a3";
|
||||
public int ReconnectionDelay { get; set; } = 1000;
|
||||
public int ReconnectionAttempts { get; set; } = 5;
|
||||
public int Timeout { get; set; } = 20000;
|
||||
public bool AutoReconnect { get; set; } = true;
|
||||
public int TaskDelayOnError { get; set; } = 5000;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,71 +1,63 @@
|
|||
using Microsoft.Extensions.Hosting;
|
||||
using Quobject.SocketIoClientDotNet.Client;
|
||||
using Sentry;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System;
|
||||
using BMA.EHR.Insignia.Service.Configuration;
|
||||
using SocketIOClient;
|
||||
using System.Security.Claims;
|
||||
|
||||
|
||||
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)
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
|
||||
|
||||
public InsigniaRequestProcessService(
|
||||
IBackgroundTaskQueue queue,
|
||||
IHttpContextAccessor httpContextAccessor)
|
||||
{
|
||||
_queue = queue;
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
|
||||
|
||||
}
|
||||
|
||||
public override Task StartAsync(CancellationToken cancellationToken)
|
||||
#region " Properties "
|
||||
|
||||
protected string? UserId => _httpContextAccessor?.HttpContext?.User?.FindFirst(ClaimTypes.NameIdentifier)?.Value;
|
||||
|
||||
protected string? FullName => _httpContextAccessor?.HttpContext?.User?.FindFirst("name")?.Value;
|
||||
|
||||
protected bool? IsPlacementAdmin => _httpContextAccessor?.HttpContext?.User?.IsInRole("placement1");
|
||||
|
||||
protected string? AccessToken => _httpContextAccessor?.HttpContext?.Request.Headers["Authorization"];
|
||||
|
||||
#endregion
|
||||
|
||||
public override async Task StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
var client = new SocketIO("https://bma-ehr.frappet.synology.me/api/v1/org-socket",
|
||||
new SocketIOOptions
|
||||
{
|
||||
// เพิ่ม token ใน handshake.auth
|
||||
Auth = new { token = AccessToken ?? "" }
|
||||
});
|
||||
|
||||
client.OnConnected += async (sender, e) =>
|
||||
{
|
||||
_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" }
|
||||
//}
|
||||
});
|
||||
Console.WriteLine("Connected to Socket.IO server");
|
||||
await client.EmitAsync("eventName", "Hello from .NET client");
|
||||
};
|
||||
|
||||
_socket.On(Socket.EVENT_CONNECT, () =>
|
||||
{
|
||||
_isConnected = true;
|
||||
Console.WriteLine("Connected to WebSocket server at: https://bma-ehr.frappet.synology.me/api/v1/org-socket");
|
||||
});
|
||||
await client.ConnectAsync();
|
||||
|
||||
_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);
|
||||
await base.StartAsync(cancellationToken);
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||
{
|
||||
var userId = "4064c2b2-0414-464a-97c6-4a47c325b9a3";
|
||||
|
||||
|
||||
while (!stoppingToken.IsCancellationRequested)
|
||||
{
|
||||
|
|
@ -74,80 +66,34 @@ public class InsigniaRequestProcessService : BackgroundService
|
|||
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}");
|
||||
var startTime = DateTime.Now;
|
||||
|
||||
await workItem(stoppingToken);
|
||||
|
||||
var endTime = DateTime.Now;
|
||||
var duration = endTime - startTime;
|
||||
|
||||
// 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 (OperationCanceledException)
|
||||
{
|
||||
|
||||
break;
|
||||
}
|
||||
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
|
||||
});
|
||||
}
|
||||
// รอสักครู่ก่อนประมวลผล task ถัดไป เพื่อป้องกันการวนลูปข้อผิดพลาด
|
||||
await Task.Delay(1000, stoppingToken);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public override Task StopAsync(CancellationToken cancellationToken)
|
||||
public override async 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);
|
||||
|
||||
|
||||
await base.StopAsync(cancellationToken);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
97
BMA.EHR.Insignia/WebSocket-Improvements.md
Normal file
97
BMA.EHR.Insignia/WebSocket-Improvements.md
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
# WebSocket Connection Improvements for InsigniaRequestProcessService
|
||||
|
||||
## ???????????????????
|
||||
|
||||
### 1. **????????? Configuration**
|
||||
- ????? `WebSocketConfiguration` class ?????????????????????
|
||||
- ?????????????????????? ???? appsettings.json
|
||||
- ?? default values ???????????????????????
|
||||
|
||||
### 2. **??????????????????????? WebSocket**
|
||||
- ??? `ImmutableList.Create()` ?????? Transports
|
||||
- ????? event handlers ????????????????????????
|
||||
- ?????? reconnection ?????????
|
||||
- Thread-safe ???? lock mechanism
|
||||
|
||||
### 3. **??????????????? Logging**
|
||||
- ??? `ILogger<T>` ??? Console.WriteLine
|
||||
- ????? emoji ??????????????? log ???????????
|
||||
- Log ??????????????????????????
|
||||
|
||||
### 4. **???????????????????**
|
||||
- Proper exception handling ????????
|
||||
- Graceful handling ??? cancellation
|
||||
- Delay ??????????????????????????????? busy loop
|
||||
|
||||
### 5. **????????????????? Notification**
|
||||
- ???????????????????????????????
|
||||
- ????????????????????????????????
|
||||
- ??????????? retry ?????????
|
||||
|
||||
## ?????????
|
||||
|
||||
### ???????????? appsettings.json
|
||||
```json
|
||||
{
|
||||
"WebSocket": {
|
||||
"Url": "https://bma-ehr.frappet.synology.me",
|
||||
"Path": "/api/v1/org-socket",
|
||||
"DefaultUserId": "4064c2b2-0414-464a-97c6-4a47c325b9a3",
|
||||
"ReconnectionDelay": 1000,
|
||||
"ReconnectionAttempts": 5,
|
||||
"Timeout": 20000,
|
||||
"AutoReconnect": true,
|
||||
"TaskDelayOnError": 5000
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Log Messages ????????
|
||||
- ?? = Service started
|
||||
- ?? = Task processing
|
||||
- ? = Success operations
|
||||
- ? = Error/Failure
|
||||
- ?? = Reconnection attempts
|
||||
- ?? = WebSocket notifications
|
||||
- ?? = Service stopping
|
||||
|
||||
## ???????????????????
|
||||
|
||||
1. **Reliability**: ???????????? WebSocket ???????????????????
|
||||
2. **Observability**: ???????????? log ???????
|
||||
3. **Configurability**: ??????????????????????? configuration
|
||||
4. **Maintainability**: ???????????????????????? ??????????
|
||||
5. **Resilience**: ?????????????????????????
|
||||
|
||||
## WebSocket Events ?????????
|
||||
|
||||
- `EVENT_CONNECT`: ???????????????
|
||||
- `EVENT_DISCONNECT`: ????????????????
|
||||
- `EVENT_ERROR`: ????????????????
|
||||
- `EVENT_CONNECT_ERROR`: ????????????????????????
|
||||
- `EVENT_RECONNECT`: ???????????????????
|
||||
- `EVENT_RECONNECT_ERROR`: ????????????????????????????
|
||||
- `EVENT_RECONNECT_FAILED`: ?????????????????????????
|
||||
|
||||
## Message Format ??????????? WebSocket
|
||||
|
||||
```javascript
|
||||
{
|
||||
"success": true/false,
|
||||
"message": "Task Finish" ???? "Task Failed",
|
||||
"payload": {
|
||||
"completedAt": "timestamp",
|
||||
"taskType": "insignia_background_processing",
|
||||
"duration": 1234.56, // milliseconds
|
||||
"status": "success" ???? "failed"
|
||||
// ?????????? error ???? error ??? stackTrace ?????
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
???????? user data:
|
||||
```javascript
|
||||
{
|
||||
"userId": "4064c2b2-0414-464a-97c6-4a47c325b9a3"
|
||||
}
|
||||
```
|
||||
12
BMA.EHR.Insignia/appsettings.websocket.example.json
Normal file
12
BMA.EHR.Insignia/appsettings.websocket.example.json
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"WebSocket": {
|
||||
"Url": "https://bma-ehr.frappet.synology.me",
|
||||
"Path": "/api/v1/org-socket",
|
||||
"DefaultUserId": "4064c2b2-0414-464a-97c6-4a47c325b9a3",
|
||||
"ReconnectionDelay": 1000,
|
||||
"ReconnectionAttempts": 5,
|
||||
"Timeout": 20000,
|
||||
"AutoReconnect": true,
|
||||
"TaskDelayOnError": 5000
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue