diff --git a/.editorconfig b/.editorconfig deleted file mode 120000 index 3ca15af8..00000000 --- a/.editorconfig +++ /dev/null @@ -1 +0,0 @@ -Settings/.editorconfig \ No newline at end of file diff --git a/csharp/Platform.Data.Doublets.Gql.Server/Data.cs b/csharp/Platform.Data.Doublets.Gql.Server/Data.cs index 6a0515f2..5f6cb511 100644 --- a/csharp/Platform.Data.Doublets.Gql.Server/Data.cs +++ b/csharp/Platform.Data.Doublets.Gql.Server/Data.cs @@ -1,17 +1,32 @@ using Platform.Data.Doublets.Memory.Split.Generic; using Platform.Memory; +using System; namespace Platform.Data.Doublets.Gql.Server { public class Data { public static string DefaultDatabaseFileName = "db.links"; + private static SplitMemoryLinks? _disposableLinks; public static ILinks CreateLinks() { // var disposableLinks = new UnitedMemoryLinks(new FileMappedResizableDirectMemory(DefaultDatabaseFileName), UnitedMemoryLinks.DefaultLinksSizeStep, new LinksConstants(enableExternalReferencesSupport: true), IndexTreeType.Default); - var disposableLinks = new SplitMemoryLinks(new FileMappedResizableDirectMemory(DefaultDatabaseFileName), new FileMappedResizableDirectMemory(DefaultDatabaseFileName + ".index"), SplitMemoryLinks.DefaultLinksSizeStep, new LinksConstants(true)); - return new SynchronizedLinks(disposableLinks.DecorateWithAutomaticUniquenessAndUsagesResolution()); + _disposableLinks = new SplitMemoryLinks(new FileMappedResizableDirectMemory(DefaultDatabaseFileName), new FileMappedResizableDirectMemory(DefaultDatabaseFileName + ".index"), SplitMemoryLinks.DefaultLinksSizeStep, new LinksConstants(true)); + return new SynchronizedLinks(_disposableLinks.DecorateWithAutomaticUniquenessAndUsagesResolution()); + } + + public static void DisposeLinks() + { + try + { + _disposableLinks?.Dispose(); + _disposableLinks = null; + } + catch (Exception) + { + // Suppress exceptions during disposal to prevent AccessViolationException + } } } } diff --git a/csharp/Platform.Data.Doublets.Gql.Server/LinksLifetimeService.cs b/csharp/Platform.Data.Doublets.Gql.Server/LinksLifetimeService.cs new file mode 100644 index 00000000..00c6dd85 --- /dev/null +++ b/csharp/Platform.Data.Doublets.Gql.Server/LinksLifetimeService.cs @@ -0,0 +1,51 @@ +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace Platform.Data.Doublets.Gql.Server +{ + public class LinksLifetimeService : IHostedService + { + private readonly ILogger _logger; + private readonly IHostApplicationLifetime _lifetime; + + public LinksLifetimeService(ILogger logger, IHostApplicationLifetime lifetime) + { + _logger = logger; + _lifetime = lifetime; + } + + public Task StartAsync(CancellationToken cancellationToken) + { + _lifetime.ApplicationStopping.Register(OnApplicationStopping); + _lifetime.ApplicationStopped.Register(OnApplicationStopped); + return Task.CompletedTask; + } + + public Task StopAsync(CancellationToken cancellationToken) + { + return Task.CompletedTask; + } + + private void OnApplicationStopping() + { + _logger.LogInformation("Application is stopping, disposing links..."); + try + { + Data.DisposeLinks(); + _logger.LogInformation("Links disposed successfully"); + } + catch (Exception ex) + { + _logger.LogWarning(ex, "Error occurred while disposing links during application stop"); + } + } + + private void OnApplicationStopped() + { + _logger.LogInformation("Application stopped"); + } + } +} \ No newline at end of file diff --git a/csharp/Platform.Data.Doublets.Gql.Server/Program.cs b/csharp/Platform.Data.Doublets.Gql.Server/Program.cs index 65f962cb..774a5385 100644 --- a/csharp/Platform.Data.Doublets.Gql.Server/Program.cs +++ b/csharp/Platform.Data.Doublets.Gql.Server/Program.cs @@ -30,6 +30,15 @@ public static int Main(params string[] args) } finally { + try + { + Log.Information("Disposing links before shutdown"); + Data.DisposeLinks(); + } + catch (Exception ex) + { + Log.Warning(ex, "Error during links disposal"); + } Log.CloseAndFlush(); } } diff --git a/csharp/Platform.Data.Doublets.Gql.Server/Startup.cs b/csharp/Platform.Data.Doublets.Gql.Server/Startup.cs index 088a010d..ab1b0397 100644 --- a/csharp/Platform.Data.Doublets.Gql.Server/Startup.cs +++ b/csharp/Platform.Data.Doublets.Gql.Server/Startup.cs @@ -29,6 +29,7 @@ public Startup(IConfiguration configuration, IWebHostEnvironment environment) // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) => services.AddSingleton(sp => Data.CreateLinks()) .AddSingleton() + .AddHostedService() .AddGraphQL((options, provider) => { options.EnableMetrics = Environment.IsDevelopment(); diff --git a/csharp/Platform.Data.Doublets.Gql.Server/StartupWithRouting.cs b/csharp/Platform.Data.Doublets.Gql.Server/StartupWithRouting.cs index 1f02a833..2de81b97 100644 --- a/csharp/Platform.Data.Doublets.Gql.Server/StartupWithRouting.cs +++ b/csharp/Platform.Data.Doublets.Gql.Server/StartupWithRouting.cs @@ -39,6 +39,7 @@ public void ConfigureServices(IServiceCollection services) => services.AddRoutin }) .AddSingleton(sp => Data.CreateLinks()) .AddSingleton() + .AddHostedService() .AddGraphQL((options, provider) => { options.EnableMetrics = Environment.IsDevelopment();