Browse Source

Limit the number of parallel requests in GraphQL.

release/4.x
Sebastian 5 years ago
parent
commit
195d99aca7
  1. 88
      backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/QueryExecutionContext.cs
  2. 12
      backend/src/Squidex.Infrastructure/Assets/ImageSharp/ImageSharpAssetThumbnailGenerator.cs

88
backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/QueryExecutionContext.cs

@ -9,6 +9,7 @@ using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Squidex.Domain.Apps.Entities.Assets;
using Squidex.Infrastructure;
@ -17,6 +18,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
{
public class QueryExecutionContext : Dictionary<string, object>
{
private readonly SemaphoreSlim maxRequests = new SemaphoreSlim(10);
private readonly ConcurrentDictionary<Guid, IEnrichedContentEntity?> cachedContents = new ConcurrentDictionary<Guid, IEnrichedContentEntity?>();
private readonly ConcurrentDictionary<Guid, IEnrichedAssetEntity?> cachedAssets = new ConcurrentDictionary<Guid, IEnrichedAssetEntity?>();
private readonly IContentQueryService contentQuery;
@ -45,7 +47,15 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
if (asset == null)
{
asset = await assetQuery.FindAssetAsync(context, id);
await maxRequests.WaitAsync();
try
{
asset = await assetQuery.FindAssetAsync(context, id);
}
finally
{
maxRequests.Release();
}
if (asset != null)
{
@ -62,7 +72,15 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
if (content == null)
{
content = await contentQuery.FindContentAsync(context, schemaId.ToString(), id);
await maxRequests.WaitAsync();
try
{
content = await contentQuery.FindContentAsync(context, schemaId.ToString(), id);
}
finally
{
maxRequests.Release();
}
if (content != null)
{
@ -77,7 +95,17 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
{
var q = Q.Empty.WithODataQuery(odata);
var assets = await assetQuery.QueryAsync(context, null, q);
IResultList<IEnrichedAssetEntity> assets;
await maxRequests.WaitAsync();
try
{
assets = await assetQuery.QueryAsync(context, null, q);
}
finally
{
maxRequests.Release();
}
foreach (var asset in assets)
{
@ -91,14 +119,24 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
{
var q = Q.Empty.WithODataQuery(odata);
var result = await contentQuery.QueryAsync(context, schemaIdOrName, q);
IResultList<IEnrichedContentEntity> contents;
await maxRequests.WaitAsync();
try
{
contents = await contentQuery.QueryAsync(context, schemaIdOrName, q);
}
finally
{
maxRequests.Release();
}
foreach (var content in result)
foreach (var content in contents)
{
cachedContents[content.Id] = content;
}
return result;
return contents;
}
public virtual async Task<IReadOnlyList<IEnrichedAssetEntity>> GetReferencedAssetsAsync(ICollection<Guid> ids)
@ -109,7 +147,17 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
if (notLoadedAssets.Count > 0)
{
var assets = await assetQuery.QueryAsync(context, null, Q.Empty.WithIds(notLoadedAssets));
IResultList<IEnrichedAssetEntity> assets;
await maxRequests.WaitAsync();
try
{
assets = await assetQuery.QueryAsync(context, null, Q.Empty.WithIds(notLoadedAssets));
}
finally
{
maxRequests.Release();
}
foreach (var asset in assets)
{
@ -128,9 +176,19 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
if (notLoadedContents.Count > 0)
{
var result = await contentQuery.QueryAsync(context, notLoadedContents);
IResultList<IEnrichedContentEntity> contents;
await maxRequests.WaitAsync();
try
{
contents = await contentQuery.QueryAsync(context, notLoadedContents);
}
finally
{
maxRequests.Release();
}
foreach (var content in result)
foreach (var content in contents)
{
cachedContents[content.Id] = content;
}
@ -139,11 +197,19 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
return ids.Select(cachedContents.GetOrDefault).NotNull().ToList();
}
public Task<IResultList<IEnrichedContentEntity>> QueryReferencingContentsAsync(string schemaIdOrName, string odata, Guid reference)
public async Task<IResultList<IEnrichedContentEntity>> QueryReferencingContentsAsync(string schemaIdOrName, string odata, Guid reference)
{
var q = Q.Empty.WithODataQuery(odata).WithReference(reference);
return contentQuery.QueryAsync(context, schemaIdOrName, q);
await maxRequests.WaitAsync();
try
{
return await contentQuery.QueryAsync(context, schemaIdOrName, q);
}
finally
{
maxRequests.Release();
}
}
}
}

12
backend/src/Squidex.Infrastructure/Assets/ImageSharp/ImageSharpAssetThumbnailGenerator.cs

@ -24,7 +24,7 @@ namespace Squidex.Infrastructure.Assets.ImageSharp
{
public sealed class ImageSharpAssetThumbnailGenerator : IAssetThumbnailGenerator
{
private readonly SemaphoreSlim semaphoreSlim = new SemaphoreSlim(Math.Max(Environment.ProcessorCount / 4, 1));
private readonly SemaphoreSlim maxTasks = new SemaphoreSlim(Math.Max(Environment.ProcessorCount / 4, 1));
public async Task CreateThumbnailAsync(Stream source, Stream destination, ResizeOptions options)
{
@ -42,8 +42,7 @@ namespace Squidex.Infrastructure.Assets.ImageSharp
var w = options.Width ?? 0;
var h = options.Height ?? 0;
await semaphoreSlim.WaitAsync();
await maxTasks.WaitAsync();
try
{
using (var image = Image.Load(source, out var format))
@ -89,7 +88,7 @@ namespace Squidex.Infrastructure.Assets.ImageSharp
}
finally
{
semaphoreSlim.Release();
maxTasks.Release();
}
}
@ -156,8 +155,7 @@ namespace Squidex.Infrastructure.Assets.ImageSharp
Guard.NotNull(source, nameof(source));
Guard.NotNull(destination, nameof(destination));
await semaphoreSlim.WaitAsync();
await maxTasks.WaitAsync();
try
{
using (var image = Image.Load(source, out var format))
@ -178,7 +176,7 @@ namespace Squidex.Infrastructure.Assets.ImageSharp
}
finally
{
semaphoreSlim.Release();
maxTasks.Release();
}
}

Loading…
Cancel
Save