From 19c4b0aa64c1039e0fce3f0a8f7c3c8c4b4e2e49 Mon Sep 17 00:00:00 2001 From: Joes Date: Tue, 3 Sep 2024 17:55:41 +0800 Subject: [PATCH 1/3] =?UTF-8?q?fix:=20Mongo=E5=88=86=E5=B8=83=E5=BC=8F?= =?UTF-8?q?=E7=BC=93=E5=AD=98=E8=BF=98=E6=9C=89=E4=B8=80=E4=BA=9B=E9=97=AE?= =?UTF-8?q?=E9=A2=98=E9=9C=80=E8=A6=81=E7=A0=94=E7=A9=B6.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 +-- .../Controllers/MongoLockController.cs | 3 ++ sample/WebApi.Test.Unit/Script.js | 33 ++++++++++++++----- .../ServiceModules/MongoModule.cs | 1 + src/EasilyNET.MongoDistributedLock/Acquire.cs | 14 +++++++- .../Attributes/IAcquire.cs | 2 +- .../DistributedLock.cs | 4 +-- .../ServiceCollectionExtensions.cs | 23 ++++++------- 8 files changed, 59 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 78d38682..ba862756 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ EasilyNET Packages - 对 MongoDB 驱动的一些封装,方便使用以及一些常用的默认配置 - 雪花 ID,一些常用的数据类型,枚举,扩展方法等 - 自动模块化注入服务,新增支持 WPF,WinForm 等项目,需使用 IHost 通用主机模式 -- MongoDB 添加 DateOnly 和 TimeOnly 的支持 +- MongoDB 添加 DateOnly 和 TimeOnly 的支持, dynamic 类型支持 - MongoDB GridFS 用法的简单支持(常用用法)和使用案例. - 在 WebAPI 中集成一些常见的过滤器和中间件 - 对 Swagger 文档添加分组,隐藏 API 和添加部分数据类型默认值显示的支持,方便前端工程师查阅 @@ -54,7 +54,7 @@ EasilyNET Packages - Some encapsulation of MongoDB driver for easy use and some common default configurations - Snowflake ID, some common data types, enumerations, extension methods, etc. - Automatic modular injection services, adding support for WPF, WinForm and other projects, using IHost common host mode -- Added support for DateOnly and TimeOnly in MongoDB +- Added support for DateOnly and TimeOnly in MongoDB, dynamic type support - Simple support for MongoDB GridFS usage (common usage) and usage examples. - Integration of some common filters and middleware in WebAPI - Added support for grouping, hiding APIs, and displaying default values for some data types in Swagger documents, making it easier for front-end engineers to refer to diff --git a/sample/WebApi.Test.Unit/Controllers/MongoLockController.cs b/sample/WebApi.Test.Unit/Controllers/MongoLockController.cs index 7240d5e0..6a341485 100644 --- a/sample/WebApi.Test.Unit/Controllers/MongoLockController.cs +++ b/sample/WebApi.Test.Unit/Controllers/MongoLockController.cs @@ -11,6 +11,9 @@ namespace WebApi.Test.Unit.Controllers; [Route("api/[controller]/[action]"), ApiController, ApiGroup("MongoLock", "v1", "基于MongoDB实现的分布式锁测试")] public class MongoLockController(IMongoLockFactory lockFactory) : ControllerBase { + [HttpPost] + public async Task BusinessTest() { } + /// /// AcquireLock /// diff --git a/sample/WebApi.Test.Unit/Script.js b/sample/WebApi.Test.Unit/Script.js index 07d2abfa..d6d49d1a 100644 --- a/sample/WebApi.Test.Unit/Script.js +++ b/sample/WebApi.Test.Unit/Script.js @@ -1,15 +1,32 @@ -import { check } from "k6"; +import { check, sleep } from "k6"; import http from "k6/http"; export const options = { - stages: [ - { duration: "30s", target: 20 }, - { duration: "1m30s", target: 10 }, - { duration: "20s", target: 0 }, - ], + stages: [ + { duration: "30s", target: 100 }, // Ramp-up to 100 users over 30s + { duration: "30s", target: 200 }, // Ramp-up to 200 users over 1 minute + { duration: "30s", target: 300 }, // Ramp-up to 300 users over 1 minute + { duration: "30s", target: 0 }, // Ramp-down to 0 users over 1 minute + ], }; export default function () { - const res = http.post("http://localhost:5046/api/MongoTest/MongoPost"); - check(res, { "status was 200": (r) => r.status == 200 }); + const url = 'http://localhost:8848/api/MongoLock/BusinessTest'; + + const payload = JSON.stringify({ + email: 'aaa', + password: 'bbb' + }); + + const params = { + headers: { + 'Content-Type': 'application/json', + }, + }; + + const res = http.post(url, params); + check(res, { "status was 200": (r) => r.status == 200 }); + + // Optional: Add a small sleep to simulate real user behavior + sleep(1); } diff --git a/sample/WebApi.Test.Unit/ServiceModules/MongoModule.cs b/sample/WebApi.Test.Unit/ServiceModules/MongoModule.cs index 42d0e28f..26e5c843 100644 --- a/sample/WebApi.Test.Unit/ServiceModules/MongoModule.cs +++ b/sample/WebApi.Test.Unit/ServiceModules/MongoModule.cs @@ -96,5 +96,6 @@ public override void ConfigureServices(ConfigureServicesContext context) }); context.Services.RegisterSerializer(new DateOnlySerializerAsString()); context.Services.RegisterSerializer(new TimeOnlySerializerAsString()); + context.Services.RegisterDynamicSerializer(); } } \ No newline at end of file diff --git a/src/EasilyNET.MongoDistributedLock/Acquire.cs b/src/EasilyNET.MongoDistributedLock/Acquire.cs index 65f85cc7..e3064d0b 100644 --- a/src/EasilyNET.MongoDistributedLock/Acquire.cs +++ b/src/EasilyNET.MongoDistributedLock/Acquire.cs @@ -6,14 +6,18 @@ namespace EasilyNET.MongoDistributedLock; /// internal sealed class Acquire : IAcquire { + private readonly IDistributedLock? _distributedLock; + /// /// 构造函数 /// /// - public Acquire(ObjectId acquireId) + /// + public Acquire(ObjectId acquireId, IDistributedLock distributedLock) { Acquired = true; AcquireId = acquireId; + _distributedLock = distributedLock; } /// @@ -29,4 +33,12 @@ public Acquire() /// public ObjectId AcquireId { get; } + + public async ValueTask DisposeAsync() + { + if (Acquired && _distributedLock is not null) + { + await _distributedLock.ReleaseAsync(this); + } + } } \ No newline at end of file diff --git a/src/EasilyNET.MongoDistributedLock/Attributes/IAcquire.cs b/src/EasilyNET.MongoDistributedLock/Attributes/IAcquire.cs index 8b4bc391..afac22b2 100644 --- a/src/EasilyNET.MongoDistributedLock/Attributes/IAcquire.cs +++ b/src/EasilyNET.MongoDistributedLock/Attributes/IAcquire.cs @@ -5,7 +5,7 @@ namespace EasilyNET.MongoDistributedLock.Attributes; /// /// IAcquire /// -public interface IAcquire +public interface IAcquire : IAsyncDisposable { /// /// true if lock successfully acquired; otherwise, false diff --git a/src/EasilyNET.MongoDistributedLock/DistributedLock.cs b/src/EasilyNET.MongoDistributedLock/DistributedLock.cs index 570f5797..3789c4b7 100644 --- a/src/EasilyNET.MongoDistributedLock/DistributedLock.cs +++ b/src/EasilyNET.MongoDistributedLock/DistributedLock.cs @@ -34,10 +34,10 @@ public async Task AcquireAsync(TimeSpan lifetime, TimeSpan timeout) var acquire = await _locks.Find(bf.Eq(c => c.Id, _lockId)).FirstOrDefaultAsync(); if (acquire is not null && await WaitSignalAsync(acquire.AcquireId, timeout) == false) { - return await TryUpdateAsync(lifetime, acquireId) ? new Acquire(acquireId) : new(); + return await TryUpdateAsync(lifetime, acquireId) ? new Acquire(acquireId, this) : new(); } } - return new Acquire(acquireId); + return new Acquire(acquireId, this); } /// diff --git a/src/EasilyNET.MongoSerializer.AspNetCore/ServiceCollectionExtensions.cs b/src/EasilyNET.MongoSerializer.AspNetCore/ServiceCollectionExtensions.cs index ab4f6837..640dde62 100644 --- a/src/EasilyNET.MongoSerializer.AspNetCore/ServiceCollectionExtensions.cs +++ b/src/EasilyNET.MongoSerializer.AspNetCore/ServiceCollectionExtensions.cs @@ -1,4 +1,5 @@ using MongoDB.Bson.Serialization; +using MongoDB.Bson.Serialization.Serializers; // ReSharper disable UnusedMethodReturnValue.Global // ReSharper disable MemberCanBePrivate.Global @@ -25,16 +26,16 @@ public static IServiceCollection RegisterSerializer(this IServiceCollection s return services; } - ///// - ///// 注册动态类型( | )序列化支持 - ///// - ///// - ///// + /// + /// 注册动态类型( | )序列化支持 + /// + /// + /// //[Obsolete("MongoDB.Drive 2.18之前和2.21之后,又默认支持动态类型的序列化了(2.19-2.20之间的版本,仅允许反序列化被视为安全的类型).暂时标记为过时.以后应该会移除")] - //public static IServiceCollection RegisterDynamicSerializer(this IServiceCollection services) - //{ - // var objectSerializer = new ObjectSerializer(type => ObjectSerializer.DefaultAllowedTypes(type) || (type.FullName is not null && type.FullName.StartsWith("<>f__AnonymousType"))); - // BsonSerializer.RegisterSerializer(objectSerializer); - // return services; - //} + public static IServiceCollection RegisterDynamicSerializer(this IServiceCollection services) + { + var objectSerializer = new ObjectSerializer(type => ObjectSerializer.DefaultAllowedTypes(type) || (type.FullName is not null && type.FullName.StartsWith("<>f__AnonymousType"))); + BsonSerializer.RegisterSerializer(objectSerializer); + return services; + } } \ No newline at end of file From b8dd2bb467294fdf4a3d91e44e1a278c071c4cc3 Mon Sep 17 00:00:00 2001 From: Joes Date: Wed, 4 Sep 2024 18:06:37 +0800 Subject: [PATCH 2/3] =?UTF-8?q?fix:=20=E6=B7=BB=E5=8A=A0=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E7=94=A8=E4=BE=8B,=E8=BF=98=E9=9C=80=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E6=9B=B4=E5=A4=A7=E7=9A=84=E5=8E=8B=E5=8A=9B.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/MongoLockController.cs | 32 +++++++++++++++++-- sample/WebApi.Test.Unit/Script.js | 8 ++--- 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/sample/WebApi.Test.Unit/Controllers/MongoLockController.cs b/sample/WebApi.Test.Unit/Controllers/MongoLockController.cs index 6a341485..a9628ae0 100644 --- a/sample/WebApi.Test.Unit/Controllers/MongoLockController.cs +++ b/sample/WebApi.Test.Unit/Controllers/MongoLockController.cs @@ -9,10 +9,38 @@ namespace WebApi.Test.Unit.Controllers; /// MongoDB分布式锁测试 /// [Route("api/[controller]/[action]"), ApiController, ApiGroup("MongoLock", "v1", "基于MongoDB实现的分布式锁测试")] -public class MongoLockController(IMongoLockFactory lockFactory) : ControllerBase +public class MongoLockController(IMongoLockFactory lockFactory, DbContext db) : ControllerBase { + /// + /// 测试锁 + /// + /// [HttpPost] - public async Task BusinessTest() { } + public async Task BusinessTest() + { + const string lockId = "64d44afda4473b85a177084d"; // 这里使用一个随机的ID作为锁ID,相当于其他锁中的Key.用来区分不同的业务的锁 + var mongoLock = lockFactory.GenerateNewLock(ObjectId.Parse(lockId)); + var acq = await mongoLock.AcquireAsync(TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(0)); + try + { + if (acq.Acquired) + { + await db.GetCollection("locks_test").InsertOneAsync(new + { + AcquiredId = acq.AcquireId + }); + } + } + catch (Exception e) + { + Console.WriteLine(e); + throw; + } + finally + { + await mongoLock.ReleaseAsync(acq); + } + } /// /// AcquireLock diff --git a/sample/WebApi.Test.Unit/Script.js b/sample/WebApi.Test.Unit/Script.js index d6d49d1a..eaa864c9 100644 --- a/sample/WebApi.Test.Unit/Script.js +++ b/sample/WebApi.Test.Unit/Script.js @@ -3,10 +3,10 @@ import http from "k6/http"; export const options = { stages: [ - { duration: "30s", target: 100 }, // Ramp-up to 100 users over 30s - { duration: "30s", target: 200 }, // Ramp-up to 200 users over 1 minute - { duration: "30s", target: 300 }, // Ramp-up to 300 users over 1 minute - { duration: "30s", target: 0 }, // Ramp-down to 0 users over 1 minute + { duration: "60s", target: 100 }, // Ramp-up to 100 users over 30s + { duration: "60s", target: 200 }, // Ramp-up to 200 users over 1 minute + { duration: "60s", target: 300 }, // Ramp-up to 300 users over 1 minute + { duration: "60s", target: 500 }, // Ramp-down to 0 users over 1 minute ], }; From 9d80e4c490d493a54515d825c7607f1481e1fcb6 Mon Sep 17 00:00:00 2001 From: Joes Date: Wed, 4 Sep 2024 19:55:18 +0800 Subject: [PATCH 3/3] =?UTF-8?q?feat:=20=E6=B5=8B=E8=AF=95Mongo=E5=88=86?= =?UTF-8?q?=E5=B8=83=E5=BC=8F=E9=94=81=E6=80=A7=E8=83=BD.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sample/WebApi.Test.Unit/Script.js | 2 +- sample/WebApi.Test.Unit/ServiceModules/MongoModule.cs | 2 ++ .../ServiceCollectionExtensions.cs | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/sample/WebApi.Test.Unit/Script.js b/sample/WebApi.Test.Unit/Script.js index eaa864c9..ae2d1a85 100644 --- a/sample/WebApi.Test.Unit/Script.js +++ b/sample/WebApi.Test.Unit/Script.js @@ -6,7 +6,7 @@ export const options = { { duration: "60s", target: 100 }, // Ramp-up to 100 users over 30s { duration: "60s", target: 200 }, // Ramp-up to 200 users over 1 minute { duration: "60s", target: 300 }, // Ramp-up to 300 users over 1 minute - { duration: "60s", target: 500 }, // Ramp-down to 0 users over 1 minute + { duration: "60s", target: 500 }, // Ramp-down to 0 users over 1 minute ], }; diff --git a/sample/WebApi.Test.Unit/ServiceModules/MongoModule.cs b/sample/WebApi.Test.Unit/ServiceModules/MongoModule.cs index 26e5c843..b8d067ad 100644 --- a/sample/WebApi.Test.Unit/ServiceModules/MongoModule.cs +++ b/sample/WebApi.Test.Unit/ServiceModules/MongoModule.cs @@ -92,6 +92,8 @@ public override void ConfigureServices(ConfigureServicesContext context) // }).Build()); // b.AddSimpleConsole(); //})); + cs.MaxConnecting = int.MaxValue; + cs.MaxConnectionPoolSize = int.MaxValue; }; }); context.Services.RegisterSerializer(new DateOnlySerializerAsString()); diff --git a/src/EasilyNET.MongoSerializer.AspNetCore/ServiceCollectionExtensions.cs b/src/EasilyNET.MongoSerializer.AspNetCore/ServiceCollectionExtensions.cs index 640dde62..f2604503 100644 --- a/src/EasilyNET.MongoSerializer.AspNetCore/ServiceCollectionExtensions.cs +++ b/src/EasilyNET.MongoSerializer.AspNetCore/ServiceCollectionExtensions.cs @@ -27,7 +27,7 @@ public static IServiceCollection RegisterSerializer(this IServiceCollection s } /// - /// 注册动态类型( | )序列化支持 + /// 注册动态类型 [ | ] 序列化支持 /// /// ///