Locking whil SyntaxCheck

This commit is contained in:
Simon Martens
2025-09-30 21:00:44 +02:00
parent 4d26bee2ba
commit 5f545bafc9
4 changed files with 26 additions and 20 deletions

View File

@@ -36,6 +36,7 @@ public class APIController : Controller {
// Options // Options
private static readonly FormOptions _defaultFormOptions = new FormOptions(); private static readonly FormOptions _defaultFormOptions = new FormOptions();
private static readonly SemaphoreSlim _syntaxCheckLock = new SemaphoreSlim(1, 1);
public APIController(IHaDocumentWrappper lib, IXMLInteractionService xmlService, IXMLFileProvider xmlProvider) { public APIController(IHaDocumentWrappper lib, IXMLInteractionService xmlService, IXMLFileProvider xmlProvider) {
@@ -78,12 +79,21 @@ public class APIController : Controller {
// [ValidateAntiForgeryToken] // [ValidateAntiForgeryToken]
[DisableFormValueModelBinding] [DisableFormValueModelBinding]
[FeatureGate(Features.SyntaxCheck, Features.AdminService)] [FeatureGate(Features.SyntaxCheck, Features.AdminService)]
public ActionResult<Dictionary<string, SyntaxCheckModel>?> GetSyntaxCheck(string? id) { public async Task<ActionResult<Dictionary<string, SyntaxCheckModel>?>> GetSyntaxCheck(string? id) {
var SCCache = _xmlService.GetSCCache(); var SCCache = _xmlService.GetSCCache();
if (_xmlProvider.HasChanged() || SCCache == null) { if (_xmlProvider.HasChanged() || SCCache == null) {
var commit = _xmlProvider.GetGitState(); await _syntaxCheckLock.WaitAsync();
SCCache = _xmlService.Test(_xmlService.GetState(), commit != null ? commit.Commit : string.Empty); try {
_xmlService.SetSCCache(SCCache); // Double-check after acquiring lock
SCCache = _xmlService.GetSCCache();
if (_xmlProvider.HasChanged() || SCCache == null) {
var commit = _xmlProvider.GetGitState();
SCCache = _xmlService.Test(_xmlService.GetState(), commit != null ? commit.Commit : string.Empty);
_xmlService.SetSCCache(SCCache);
}
} finally {
_syntaxCheckLock.Release();
}
} }
return Ok(SCCache); return Ok(SCCache);
} }

View File

@@ -81,13 +81,13 @@ public class WebSocketMiddleware : IMiddleware {
} }
result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None); result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
} catch (WebSocketException ex) { } catch (WebSocketException ex) {
_openSockets!.Remove(webSocket); break;
} }
} }
try { try {
await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None); await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);
} catch (WebSocketException ex) { } catch (WebSocketException ex) {
_openSockets.Remove(webSocket); // Socket already closed
} }
_openSockets!.Remove(webSocket); _openSockets!.Remove(webSocket);
} }
@@ -124,13 +124,17 @@ public class WebSocketMiddleware : IMiddleware {
private async Task _SendToAll<T>(T msg) { private async Task _SendToAll<T>(T msg) {
if (_openSockets == null) return; if (_openSockets == null) return;
foreach (var socket in _openSockets) { var socketsToRemove = new List<WebSocket>();
foreach (var socket in _openSockets.ToList()) {
try { try {
await socket.SendAsync(_SerializeToBytes(msg), WebSocketMessageType.Text, true, CancellationToken.None); await socket.SendAsync(_SerializeToBytes(msg), WebSocketMessageType.Text, true, CancellationToken.None);
} catch (WebSocketException ex) { } catch (WebSocketException ex) {
_openSockets.Remove(socket); socketsToRemove.Add(socket);
} }
} }
foreach (var socket in socketsToRemove) {
_openSockets.Remove(socket);
}
} }
private ArraySegment<byte> _SerializeToBytes<T>(T o) { private ArraySegment<byte> _SerializeToBytes<T>(T o) {

View File

@@ -2,10 +2,10 @@ name: hamann-ausgabe-staging
services: services:
hamann-staging: hamann-staging:
build: . build: .
ports:
- "5000:5000"
volumes: volumes:
- hamann_staging_data:/app/data - hamann_staging_data:/app/data
networks:
- caddy
environment: environment:
- ASPNETCORE_URLS=http://+:5000 - ASPNETCORE_URLS=http://+:5000
- DOTNET_ENVIRONMENT=Staging - DOTNET_ENVIRONMENT=Staging
@@ -17,8 +17,4 @@ services:
volumes: volumes:
hamann_staging_data: hamann_staging_data:
external: true
networks:
caddy:
external: true external: true

View File

@@ -2,10 +2,10 @@ name: hamann-ausgabe
services: services:
hamann-service: hamann-service:
build: . build: .
ports:
- "5000:5000"
volumes: volumes:
- hamann_data:/app/data - hamann_data:/app/data
networks:
- caddy
environment: environment:
- ASPNETCORE_URLS=http://+:5000 - ASPNETCORE_URLS=http://+:5000
- DOTNET_ENVIRONMENT=Production - DOTNET_ENVIRONMENT=Production
@@ -18,7 +18,3 @@ services:
volumes: volumes:
hamann_data: hamann_data:
external: true external: true
networks:
caddy:
external: true