प्लेबुक

CQRS (कमांड क्वेरी रिस्पॉन्सिबिलिटी सेग्रीगेशन) पाइपलाइन कैसे काम करती है? कमांड और क्वेरी फ़्लो का एनाटॉमी (CQRS)

CQRS अनुरोध पाइपलाइन क्या है? HTTP अनुरोध नियंत्रक, MediatR, पाइपलाइन व्यवहार, हैंडलर, आउटबॉक्स और रीड मॉडल के माध्यम से कैसे आगे बढ़ता है?

सीक्यूआरएस- निर्णयों की शारीरिक रचना

भाग 2 का 4

सीक्यूआरएस फ्रेमवर्क सिंटैक्स के साथ नहीं; निर्णय, पैमाने और उत्पादन तनाव की जांच करने वाली चार-भाग वाली इंजीनियरिंग पुस्तक।

Command and query pipelines flowing through a CQRS architecture

क्या होता है जब एक HTTP अनुरोध सिस्टम पर आता है? सत्यापन कहां काम करता है, लेनदेन कब खोला जाता है, डोमेन नियम किस स्तर पर लागू होते हैं? CQRS का उपयोग करने वाली प्रणाली में, यह यात्रा क्लासिक CRUD आर्किटेक्चर से अलग है। इस लेख में, हम उन चरणों की जांच करेंगे जो एक अनुरोध एपीआई से डेटाबेस से रीडिंग मॉडल तक होता है।

सीक्यूआरएस से अपरिचित पाठक के लिए, सबसे छोटा शब्दकोश यह है: कमांड सिस्टम को बदलने का इरादा है; प्रश्न सिस्टम को बदले बिना जानकारी का अनुरोध करता है; हैंडलर इस अनुरोध का हैंडलर है। MediatR जैसा मध्यस्थ नियंत्रक को सही हैंडलर को सीधे पहचानने के बजाय अनुरोध को उचित स्ट्रीम पर अग्रेषित करने की अनुमति देता है।```text POST /orders ↓ Controller ↓ Mediator.Send(command) ↓ Pipeline behaviors ↓ Command handler ↓ Aggregate + Repository ↓ Database


पाइपलाइन व्यवहार सामान्य तकनीकी नियंत्रण हैं जिन्हें हम हर कमांड में दोबारा लिखना नहीं चाहते हैं। इनमें से कोई भी व्यावसायिक नियम नहीं हैं; बिजनेस नियम हैंडलर और एग्रीगेट में रहता है।```text
ValidationBehavior
  ↓
AuthorizationBehavior
  ↓
LoggingBehavior
  ↓
MetricsBehavior
  ↓
RetryBehavior (yalnızca güvenli işlemlerde)
  ↓
TransactionBehavior
  ↓
Handler
```लेन-देन अंत में खुलता है; क्योंकि हम अनावश्यक रूप से डेटाबेस कनेक्शन को स्थानांतरित नहीं करना चाहते हैं और ऐसे अनुरोध को लॉक नहीं करना चाहते हैं जो अमान्य, अनधिकृत या समय से पहले खारिज हो सकता है। एक बार जब हम हैंडलर तक पहुंच जाते हैं, तो अब हम व्यावसायिक निर्णय को परमाणु रूप से लागू करने के लिए तैयार हैं।

**एग्रीगेट** सिस्टम के व्यावसायिक नियमों को संरक्षित करता है - अर्थात, अपरिवर्तनीय - जिन्हें कभी नहीं तोड़ा जाना चाहिए। उदाहरण के लिए, यदि पूरा किया गया ऑर्डर दोबारा रद्द नहीं किया जा सकता है, तो इस नियम को ऑर्डर एग्रीगेट में बनाए रखा जाना चाहिए, न कि कंट्रोलर में।

क्वेरी पक्ष एक अलग पथ का अनुसरण करता है। उसी क्रम के लिए, उपयोगकर्ता को संपूर्ण डोमेन ऑब्जेक्ट नहीं, बल्कि स्क्रीन के लिए उपयुक्त एक संक्षिप्त दृश्य की आवश्यकता हो सकती है:```text
GET /orders
  ↓
Authorization
  ↓
Cache (uygunsa)
  ↓
Read database / Search index
  ↓
OrderSummary DTO
  ↓
Frontend

पहले उल्लेख पर अवधारणाएँ```text

📦 Handler Tek bir command veya query'nin uygulama iş akışını yürütür.

📦 Mediator Controller'ın handler'ı doğrudan bilmeden isteği doğru işleyiciye göndermesini sağlar.

📦 Pipeline Behavior Validation, authorization veya logging gibi her istekte çalışan ortak teknik katmandır.

📦 Repository Aggregate'i yükleyen ve kalıcı olarak saklayan uygulama sınırıdır.

📦 DTO Domain modelin tamamını değil, bir ekranın ihtiyacı olan veriyi taşır.


जब आप हैंडलर उदाहरण पढ़ते हैं, तो इस अंतर को ध्यान में रखें: हैंडलर बस व्यावसायिक निर्णय लागू करता है। सत्यापन, प्राधिकरण और लॉगिंग हैंडलर में शामिल नहीं हैं; इन्हें पाइपलाइन व्यवहार द्वारा हल किया जाता है। इस तरह, हैंडलर छोटा रहता है और प्रत्येक अनुरोध समान सुरक्षा/ट्रेसेबिलिटी नियमों को पारित करता है।

हम अक्सर CQRS को दो फ़ोल्डर्स, कुछ MediatR हैंडलर और एक कैश के रूप में देखते हैं। यह छवि भ्रामक है. CQRS का मुख्य कार्य कोड को विभाजित करना नहीं है; यह **निर्णयों जो किसी सिस्टम की स्थिति को बदलते हैं** और **उस स्थिति के बारे में जानकारी का अनुरोध करने वाले अनुरोधों** के बीच अंतर करना है।

यह CQRS-एनाटॉमी ऑफ डिसीजन संग्रह का दूसरा भाग है। पहले भाग में हम बात करेंगे कि पृथक्करण क्यों आवश्यक हो गया है। यहां हम तंत्र में आते हैं: कमांड किन गेटों से होकर गुजरता है, क्वेरी को उसी पथ का अनुसरण क्यों नहीं करना चाहिए, और रीड मॉडल कब एक अलग सिस्टम बन जाता है?

## शुरुआती बिंदु: एक अनुरोध, दो अलग-अलग इरादे

`CreateOrder` एक कमांड है. वह सिस्टम में एक नई वास्तविकता जोड़ना चाहते हैं। यह नियमों को निष्पादित करता है, प्राधिकरण का अनुरोध करता है, लेनदेन खोलता है और ऑडिट योग्य होना चाहिए।

`GetOrderSummary` एक प्रश्न है. यह कोई नई वास्तविकता उत्पन्न नहीं करता. तेज़, संकीर्ण, स्क्रीन-अनुकूल दृश्य लौटाना चाहता है। इसे समान समुच्चय को लोड करने, डोमेन नियम चलाने या राइट-साइड लॉक के साथ प्रतिस्पर्धा करने की आवश्यकता नहीं है।

इस भेद का एल्गोरिथम निहितार्थ स्पष्ट है: कमांड पक्ष पर, लागत को अक्सर सत्यापन और स्थिरता के लिए माना जाता है; क्वेरी पक्ष पर, पूछे गए डेटा की मात्रा के साथ लागत बढ़ती है। सूची स्क्रीन के लिए समग्र ग्राफ़ को पार करने के बजाय एक अनुरूपित रीड मॉडल का उपयोग करने से अनावश्यक I/O और संज्ञानात्मक भार दोनों कम हो जाते हैं।

## कमांड पाइपलाइन: निर्णय का सुरक्षित मार्ग

कमांड पक्ष पर, उद्देश्य केवल `handler` को कॉल करना नहीं है। व्यावसायिक निर्णय तक पहुंचने से पहले अनुरोध को सिस्टम के सामान्य नियमों से गुजरना होगा।```text
API
  → Authentication / Authorization
  → Validation
  → Idempotency check
  → Transaction
  → Command Handler
  → Aggregate + Domain Rules
  → Persist + Outbox
  → Commit
```स्यूडोकोड:```text
handle(command):
  authorize(command.actor)
  validate(command)
  return idempotency.execute(command.key):
    begin transaction
    aggregate = repository.load(command.aggregateId)
    aggregate.apply(command)
    repository.save(aggregate)
    outbox.store(aggregate.domainEvents)
    commit transaction
```हर कदम की एक ही जिम्मेदारी होती है. सत्यापन किसी व्यावसायिक नियम को प्रतिस्थापित नहीं करता है; अमान्य फॉर्म को जल्दी अस्वीकार कर देता है। प्राधिकरण जाँच करता है कि निर्णय स्वामी का है या नहीं। समुच्चय अपरिवर्तनीयों को सुरक्षित रखता है। दूसरी ओर, आउटबॉक्स यह सुनिश्चित करता है कि स्थायी स्थिति और प्रकाशित होने वाली घटना समान लेनदेन सीमा के भीतर होती है।

C# पक्ष पर, मध्यस्थ इस प्रवाह को व्यावहारिक बनाता है:```csharp
public sealed record PlaceOrder(Guid CustomerId, IReadOnlyList<OrderLine> Lines) : IRequest<OrderId>;

public sealed class PlaceOrderHandler : IRequestHandler<PlaceOrder, OrderId>
{
    public async Task<OrderId> Handle(PlaceOrder command, CancellationToken ct)
    {
        var order = Order.Place(command.CustomerId, command.Lines);
        await repository.AddAsync(order, ct);
        await outbox.AddAsync(order.DomainEvents, ct);
        return order.Id;
    }
}
```हैंडलर छोटा रहता है क्योंकि ऑडिट, माप, सत्यापन या पुनः प्रयास जैसी क्रॉस-कटिंग जिम्मेदारियां पाइपलाइन व्यवहार में स्थानांतरित हो जाती हैं। इसका लाभ यह है कि प्रत्येक हैंडलर हाथ से समान व्यवहार को पुन: उत्पन्न नहीं करता है। कीमत कॉल श्रृंखला की दृश्यता खोने का जोखिम है। इसलिए व्यवहार अनुक्रम को स्पष्ट रूप से प्रलेखित और देखा जाना चाहिए।

## क्वेरी पाइपलाइन: उतना ही पढ़ें जितना आपको चाहिए

प्रश्न पक्ष पर, मूल प्रश्न यह है: उपयोगकर्ता किस विलंबता बजट के भीतर क्या जानकारी चाहता है? इस प्रश्न का उत्तर डोमेन मॉडल नहीं है, बल्कि उपयोग परिदृश्य है।```text
API
  → Authorization for the view
  → Query Handler
  → Read model / cache / search index
  → DTO shaped for the screen
```ऑर्डर सूची के लिए `Order` समुच्चय, ग्राहक संबंध और इन्वेंट्री नियमों को फिर से लोड करना अक्सर अनावश्यक होता है। क्वेरी हैंडलर सीधे उन फ़ील्ड का चयन करता है जिनकी स्क्रीन को आवश्यकता होती है। इस प्रकार, लागत लगभग संपूर्ण डोमेन ग्राफ़ के बजाय लौटाई गई पंक्तियों और स्तंभों की संख्या तक सीमित है।```csharp
public sealed record GetOrderSummary(Guid OrderId) : IRequest<OrderSummaryDto?>;

public sealed class GetOrderSummaryHandler : IRequestHandler<GetOrderSummary, OrderSummaryDto?>
{
    public Task<OrderSummaryDto?> Handle(GetOrderSummary query, CancellationToken ct) =>
        readDb.OrderSummaries
            .Where(x => x.Id == query.OrderId)
            .Select(x => new OrderSummaryDto(x.Id, x.Status, x.Total, x.UpdatedAt))
            .SingleOrDefaultAsync(ct);
}
```यहां `DTO` डोमेन को छिपाने के लिए कोई सजावट नहीं है; यह एक वाचन समझौता है. स्क्रीन बदलने पर रीड मॉडल बदल सकता है। व्यावसायिक नियम बदलने पर कमांड मॉडल बदल सकता है। दोनों परिवर्तनों का एक ही गति से घटित होना आवश्यक नहीं है।

## तार्किक सीक्यूआरएस और भौतिक सीक्यूआरएस

अधिकांश टीमों के लिए पहला चरण तार्किक CQRS है: कमांड और क्वेरी कोड में अलग-अलग हैं, लेकिन वे समान रिलेशनल डेटाबेस का उपयोग करते हैं। ACID लेनदेन सुरक्षित हैं, संचालन लागत कम है, और डिबगिंग सरल है।

भौतिक सीक्यूआरएस में, रीड मॉडल को एक अलग डेटा स्टोर, कैश या सर्च इंडेक्स में ले जाया जाता है। इससे रीड साइड को स्वतंत्र रूप से स्केल करने का अवसर मिलता है; लेकिन बदले में डेटा ताजगी, प्रक्षेपण त्रुटियां और पुनर्निर्माण प्रक्रियाएं आती हैं। इसलिए, शारीरिक अलगाव कोई प्रदर्शन कल्पना नहीं बल्कि एक सिद्ध बाधा का उत्तर है।

| चुनाव | कमाई | स्वीकृत मूल्य |
| --- | --- | --- |
| तार्किक सीक्यूआरएस | कम परिचालन लागत, मजबूत स्थिरता | पढ़ना और लिखना समान बुनियादी ढांचे को साझा करते हैं |
| भौतिक सीक्यूआरएस | स्वतंत्र स्केलिंग, स्क्रीन-फिट मॉडल | अंतिम स्थिरता, प्रक्षेपण संचालन |

## लिखने वाले मॉडल से पढ़ने वाले मॉडल तक: सीडीसी या आउटबॉक्स?

भौतिक पृथक्करण में महत्वपूर्ण प्रश्न यह है कि डेटा कैसे प्रवाहित होता है। चेंज डेटा कैप्चर लॉग से डेटाबेस परिवर्तनों को कैप्चर कर सकता है; यह मौजूदा सिस्टम को छुए बिना रीप्ले के लिए शक्तिशाली हो सकता है। लेकिन यह संदेश अनुबंध को डेटाबेस स्कीमा के करीब लाता है।

आउटबॉक्स दृष्टिकोण उसी लेनदेन में डोमेन इवेंट को आउटबॉक्स तालिका में लिखता है। एक रिले इन रिकॉर्ड्स को ब्रोकर तक ले जाती है; उपभोक्ता उदासीन व्यवहार करते हैं। इस प्रकार `database write başarılı, event publish başarısız` दुविधा प्रबंधनीय हो जाती है। लेकिन रिले, पुनः प्रयास, डेड-लेटर मॉनिटरिंग और उपभोक्ता निष्क्रियता अब डिज़ाइन का हिस्सा हैं।```text
Command commit
  → Outbox record
  → Relay publishes event
  → Projection consumes event
  → Read model updates
```इस प्रवाह में, बिल्कुल एक बार के वादे के बजाय कम से कम एक बार डिलीवरी और निष्क्रिय प्रसंस्करण को डिजाइन करना अधिक यथार्थवादी है। उदाहरण के लिए, प्रक्षेपण इवेंट आईडी रिकॉर्ड करता है; यदि वही घटना दोबारा घटती है, तो इससे दृश्य दूसरी बार नहीं बदलता है।

## क्यों टूट जाते हैं भोले-भाले समाधान?

- हैंडलर से सीधे ब्रोकर को एक संदेश भेजना: लेन-देन वापस करते समय संदेश का उपभोग पहले ही किया जा चुका होगा।
- प्रत्येक क्वेरी के लिए एग्रीगेट लोड हो रहा है: डोमेन नियमों और जुड़ावों के साथ सूची स्क्रीन अनावश्यक रूप से महंगी हो जाती हैं।
- रीड मॉडल विलंब को एक त्रुटि मानते हुए: कुछ स्क्रीनों को ताज़ा डेटा की आवश्यकता होती है, कुछ विलंब के सेकंड को सहन करते हैं। यह भेद उत्पाद के साथ निर्धारित किया जाना चाहिए।
- भौतिक सीक्यूआरएस के साथ हर समस्या का समाधान: दूसरा डेटा स्टोर सिर्फ तकनीक नहीं है बल्कि स्थायी परिचालन ओवरहेड है।

## निर्णय चेकलिस्ट

1. क्या कमांड सफलता की स्थिति और निष्क्रियता स्विच चालू हैं?
2. क्या प्रत्येक अपरिवर्तनीय समग्र सीमा पर संरक्षित है?
3. क्या क्वेरी को डोमेन के बजाय उपयोग परिदृश्य के डीटीओ के अनुसार आकार दिया गया है?
4. क्या रीड मॉडल विलंब के लिए उत्पाद भाषा में एक अपेक्षा परिभाषित की गई है?
5. जब प्रोजेक्शन का पुनर्निर्माण किया जाएगा तो सिस्टम की निगरानी और सत्यापन कैसे किया जाएगा?

सीक्यूआरएस असीमित पैमाने का स्वचालित टिकट नहीं है। जब सही ढंग से उपयोग किया जाता है, तो निर्णयों को एक पाइपलाइन में बनाया जा सकता है; यह पढ़ने को एक ऐसे मॉडल में बदल देता है जो आवश्यकताओं के अनुरूप हो। इस तरह, सिस्टम अधिक दृश्यमान और परिवर्तन के प्रति अधिक प्रतिरोधी बन जाता है।

अगले भाग में, यह तर्क एकल सेवा सीमा से आगे जाएगा: हम वितरित सिस्टम में इवेंट ब्रोकरों, अनुमानों और रोलबैक रणनीतियों के साथ सीक्यूआरएस की जांच करेंगे।

## रीड मॉडल क्या है?

पढ़ा गया मॉडल लेखन पक्ष पर डोमेन मॉडल की प्रतिलिपि नहीं है; यह स्क्रीन की आवश्यकताओं के लिए तैयार किया गया दृश्य है।```text
Orders (write model)
Id | CustomerId | Status | Lines | Rules
          ↓ Projection
OrderSummary (read model)
Id | CustomerName | Status | Total | BadgeColor
```## सीडीसी बनाम आउटबॉक्स

| कसौटी | सीडीसी | आउटबॉक्स |
| --- | --- | --- |
| डोमेन इवेंट का आशय | अप्रत्यक्ष | खुला |
| डीबी स्कीमा निर्भरता | उच्च | निचला |
| दोबारा खेलना | मजबूत | मजबूत |
| घटना सामग्री नियंत्रण | सीमित | पूर्ण |
| माइक्रोसर्विस संचार | निर्भर करता है | बहुत किफायती |

## उत्पादन में अनुभवहीन समाधान क्यों विफल हो जाते हैं?```text
Handler
  → DbContext.SaveChanges()
  → Message publish
```यदि दूसरा चरण विफल हो जाता है, तो डेटा लिखा जाता है और ईवेंट खो जाता है। या, जब लेन-देन वापस किया जा रहा हो, तो निम्न कॉल पहले ही दुष्प्रभाव उत्पन्न कर चुकी हो:```text
await emailService.Send(...)
```इसलिए, आउटबॉक्स ईवेंट को उसी लेनदेन सीमा में स्थायी परिवर्तन के साथ प्रकाशित करने के लिए लेता है; पुनः प्रयास-प्रतिरोधी उपभोक्ताओं में, ई-मेल जैसे दुष्प्रभावों को प्रतिबद्ध होने के बाद नियंत्रित किया जाता है।

## वास्तविक अनुरोध कैसे प्रवाहित होता है?```text
POST /orders
  ↓
Controller
  ↓
Mediator.Send()
  ↓
Validation → Authorization → Logging → Metrics → Transaction
  ↓
Handler
  ↓
Aggregate
  ↓
Repository + Outbox
  ↓
Commit
  ↓
Relay → Broker / Kafka
  ↓
Projection
  ↓
Read database
  ↓
GET /orders → Query handler → DTO → Frontend
```CQRS एक स्वचालित पैमाना नहीं है. लेकिन यदि आप यह समझा सकते हैं कि पाइपलाइन में प्रत्येक चरण क्यों मौजूद है, तो यह आपके सिस्टम में जिम्मेदारी के सचेत पृथक्करण का परिचय देता है। यदि आप इसे समझा नहीं सकते हैं, तो हो सकता है कि आप अभी तक CQRS का उपयोग करने के लिए तैयार न हों।

## मुझे इस प्रवाह के बारे में क्यों जानना चाहिए?

यदि आप जानते हैं कि अनुरोध किन परतों से होकर गुजरता है:

- आप कंट्रोलर या हैंडलर में बेतरतीब ढंग से वैलिडेशन नहीं लिखते हैं।
- आप व्यवसाय नियम को HTTP परत में नहीं रखते हैं, आप इसे समग्र सीमा पर सुरक्षित रखते हैं।
- आप लेनदेन को आवश्यकता से पहले न खोलें।
- आप लॉगिंग, प्राधिकरण और माप कोड के साथ हैंडलर को बड़ा नहीं करते हैं।
- आप क्रॉस-कटिंग चिंताओं को पाइपलाइन में ले जाते हैं।

क्वेरी पक्ष पर अंतर भी उतना ही व्यावहारिक है:```text
Sipariş detayı
  → Order aggregate
  → kurallar ve davranış için doğru model

Sipariş listesi
  → OrderSummaryDto
  → ekrana hızlı ve dar bir görünüm
```इस अंतर को देखने का मतलब है कि CQRS एक फ़ोल्डर लेआउट नहीं है; यह आपको हर ज़िम्मेदारी को सही जगह पर रखने के लिए एक अनुशासन के रूप में उपयोग करने की अनुमति देता है।

FAQ

Frequently asked questions

हैंडलर क्या है?

एकल कमांड या क्वेरी के एप्लिकेशन वर्कफ़्लो को निष्पादित करता है।

मध्यस्थ क्या है?

यह सुनिश्चित करता है कि नियंत्रक सीधे हैंडलर को जाने बिना सही हैंडलर को अनुरोध भेजता है।

"सीक्यूआरएस (कमांड क्वेरी रिस्पॉन्सिबिलिटी सेग्रीगेशन) पाइपलाइन कैसे काम करती है? कमांड और क्वेरी फ्लो का एनाटॉमी" आपको क्या बताता है?

CQRS अनुरोध पाइपलाइन क्या है? HTTP अनुरोध नियंत्रक, MediatR, पाइपलाइन व्यवहार, हैंडलर, आउटबॉक्स और रीड मॉडल के माध्यम से कैसे आगे बढ़ता है?

इंजीनियरिंग सिद्धांत सीखे गए

  • CQRS दो डेटाबेस नहीं हैं; यह स्वीकार करना होगा कि पढ़ना और लिखना अलग-अलग जिम्मेदारियाँ हैं।
  • पाइपलाइन संचालकों से बार-बार की जाने वाली जाँच को हटा देती है; व्यावसायिक निर्णय को दृश्यमान छोड़ देता है।
  • भौतिक पृथक्करण केवल तभी मूल्यवान है जब विलंबता, पुनः प्रयास और डेटा ताज़ाता को उत्पाद निर्णय के रूप में डिज़ाइन किया गया हो।

जारी रखें पढ़ रहे हैं

जारी रखें पढ़ रहे हैं

श्रृंखला में अगला

निबंध

वितरित सिस्टम में CQRS (कमांड क्वेरी रिस्पॉन्सिबिलिटी सेग्रीगेशन): इवेंट, ब्रोकर और प्रोजेक्शन

वितरित सिस्टम में CQRS कैसे काम करता है? डोमेन इवेंट, संदेश ब्रोकर, प्रोजेक्शन, आउटबॉक्स, निष्क्रियता और अंतिम स्थिरता निर्णयों की शुरू से अंत तक जांच…

श्रृंखला में अगला

निबंध

सीआरयूडी (बनाएं, पढ़ें, अपडेट करें, हटाएं) से सीक्यूआरएस (कमांड क्वेरी रिस्पॉन्सिबिलिटी सेग्रीगेशन) तक: समस्या मॉडल है, कोड नहीं

CQRS क्या है, CRUD और CQRS में क्या अंतर है और CQRS का उपयोग कब किया जाना चाहिए? एक मार्गदर्शिका यह बताती है कि बड़ी प्रणालियों में एक ही मॉडल पर्याप्त…

वही सिलसिला

निबंध

उत्पादन में CQRS (कमांड क्वेरी रिस्पॉन्सिबिलिटी सेग्रीगेशन): संगति, त्रुटियाँ और पुनर्प्राप्ति रणनीतियाँ

CQRS उत्पादन परिवेश में सुरक्षित रूप से कैसे काम करता है? संगति अंतराल, डुप्लिकेट ईवेंट, अनुक्रम भ्रष्टाचार, प्रक्षेपण पुनर्प्राप्ति, पुनः प्रयास, डीएलक्यू…

Paylaş