معرفی Carom؛ کتابخانه تابآوری بدون وابستگی برای .NET
نویسنده: راویAI
تاریخ: ۱۴۰۵/۰۶/۰۶ ۰۹:۱۵
آدرس: www.dntips.ir
.NET است که با هدف حذف وابستگیهای خارجی و اعمال بهترین شیوههای برنامهنویسی به صورت پیشفرض طراحی شده است. این ابزار به توسعهدهندگان کمک میکند تا خطاهای احتمالی در اجرای کد را به شکلی بهینه و بدون وقفه مدیریت کنند..NET 8 و .NET 10 پشتیبانی میکند و هسته اصلی آن بر پایه netstandard2.0 توسعه یافته است. این ویژگی باعث میشود تا برنامههای قدیمیتر مبتنی بر .NET Framework نیز بتوانند از قابلیتهای Carom بهرهمند شوند.ASP.NET Core و EF Core و همچنین OpenTelemetry ارائه شده است که برای محیطهای net8.0 و net10.0 بهینه شدهاند. تمرکز اصلی این پروژه بر کاهش تخصیص حافظه و افزایش سرعت اجرا در محیطهای عملیاتی است.چکیده: کتابخانههای تابآوری (Resilience Libraries) ستون فقرات معماریهای مدرن مبتنی بر میکروسرویس و سیستمهای توزیعشده در اکوسیستم داتنت محسوب میشوند. در سال ۲۰۲۶، تغییر مدل ارائهی پکیج دوتایی (Binary Distribution Model) کتابخانهی شناختهشدهی Polly و افزودن لایسنس تجاری OSMF برای بستههای منتشرشده روی NuGet، چالشهای حقوقی و فنی نوینی را برای سازمانها و تیمهای نرمافزاری ایجاد کرد. این مقاله به بررسی جامع و ارزیابی فنی کتابخانهی نوظهور و سبکوزن Carom (تحت لایسنس MPL-2.0) بهعنوان گزینهای جایگزین میپردازد. در ادامه، ضمن تحلیل تفاوتهای معماری و همسنجی الگوهای کلیدی تابآوری (از جمله Retry، Circuit Breaker، Bulkhead، Rate Limiting، Fallback و Hedging)، چالشها و مزایای مهاجرت به این ابزار ارزیابی خواهد شد.
ResiliencePipeline).dotnet add package نصب میگردد، شرایط حقوقی یکسانی ندارند.Carom) و بستهی اکستنشنها فاقد هرگونه پکیج شخص ثالث (Third-Party) هستند. حجم DLL هسته تنها ۱۹ کیلوبایت است.netstandard2.0 است و در کنار پشتیبانی از .NET Framework و تمامی نسخههای مدرن داتنت، سازگاری کاملی با .NET 8 و .NET 10 در بستههای اکوسیستمی (مانند EF Core، OpenTelemetry و Health Checks) دارد.Stopwatch.GetTimestamp) طراحی شده است؛ بنابراین پرشهای ناشی از تصحیح زمان سیستم توسط پروتکل NTP، الگوریتمهای Rate Limiter یا مدتزمان باز بودن Circuit Breaker را مختل نمیکند.ResiliencePipelineBuilder) استفاده میکند، Carom از متدهای استاتیک شفاف و سبک (مانند Carom.ShotAsync) بهره میبرد.// --- رویکرد Polly v8 ---
var pipeline = new ResiliencePipelineBuilder()
.AddRetry(new RetryStrategyOptions
{
MaxRetryAttempts = 3,
Delay = TimeSpan.FromMilliseconds(100),
BackoffType = DelayBackoffType.Exponential,
UseJitter = true
})
.Build();
var result = await pipeline.ExecuteAsync(async ct => await api.CallAsync(ct));
// --- رویکرد معادل در Carom ---
var result = await Carom.ShotAsync(() => api.CallAsync(), retries: 3);Bounce مستقیماً به پیکربندی تلاش مجدد پیوند میزند.// پیادهسازی در Carom var bounce = Bounce.Times(5).WithTimeout(TimeSpan.FromSeconds(30)); var data = await Carom.ShotAsync(() => apiClient.FetchAsync(), bounce);
نکتهی فنی: در Carom، سازوکار Timeout بهدرستی بر روی فراخوانیهای ناهمگام (Async) و از طریق لغو ساختاریافته اعمال میگردد. متدهای همگام (Synchronous) فاقد مکانیزم لغو اجباری هستند.// --- رویکرد Polly v8 ---
var pollyBreaker = new ResiliencePipelineBuilder()
.AddCircuitBreaker(new CircuitBreakerStrategyOptions
{
FailureRatio = 0.5,
MinimumThroughput = 10,
BreakDuration = TimeSpan.FromSeconds(30)
})
.Build();
// --- رویکرد معادل در Carom ---
var cushion = Cushion.ForService("payment-api")
.OpenAfter(failures: 5, within: 10)
.HalfOpenAfter(TimeSpan.FromSeconds(30));
var payment = await CaromCushionExtensions.ShotAsync(
() => paymentApi.Charge(),
cushion);مزیت معماری: در صورت باز بودن مدار (Open State)، سیستم بلافاصله با خطا برمیگردد (Fail-Fast) و درخواستهای بیهوده وارد چرخهی Retry نخواهند شد.
Compartment و با کنترل سختگیرانهی ظرفیت صف در زمان رزرو پیادهسازی میکند:var dbCompartment = Compartment.ForResource("database")
.WithMaxConcurrency(10) // حداکثر همزمانی مجاز
.WithQueueDepth(5) // حداکثر ظرفیت صف انتظار
.Build();
var rows = await CaromCompartmentExtensions.ShotAsync(
() => db.QueryAsync(sql),
dbCompartment);var throttle = Throttle.ForService("external-api")
.WithRate(100, TimeSpan.FromSeconds(1)) // ۱۰۰ درخواست در ثانیه
.WithBurst(20) // تحمل ۲۰ درخواست مازاد لحظهای
.Build();
var result = await CaromThrottleExtensions.ShotAsync(
() => api.CallAsync(),
throttle);var config = await new Func<Task<AppConfig>>(() => configService.LoadAsync())
.PocketAsync(AppConfig.Default);var config = Masse.WithAttempts(3)
.After(TimeSpan.FromMilliseconds(500))
.When(r => IsStale(r));
var result = await CaromMasseExtensions.ShotWithHedgingAsync(
ct => ReadReplica(ct),
config);| شاخص ارزیابی | Polly (v8) | Carom (v1.7.0) |
| لایسنس پکیج NuGet | تجاری (OSMF EULA برای درآمد بالا) | کامپوننت باز و شفاف (MPL-2.0) |
| تعداد وابستگیها | چندگانه (بسته به اکستنشنها) | صفر (Zero Dependencies) |
| حجم کتابخانه | متوسط به بالا | بسیار سبک (Core: 19KB) |
| یکپارچگی با DI و میزبانی | عمیق (AddResiliencePipeline) | در حال توسعه (نیازمند Wrapper ساده) |
| ابزار دقیق و تلهمتری | کامل و یکپارچه با OpenTelemetry | بستهی جدید و در حال بلوغ |
| پشتیبانی و جامعهی کاربری | بیش از ۱۰ سال سابقه و اکوسیستم وسیع | جامعه نوپا و توسعه چابک |
| مبنای زمانبندی داخلی | سنتی / ترکیبی | کاملاً Monotonic Clock |
dotnet add package Carom dotnet add package Carom.Extensions