इवेंट सोर्सिंग और REST


17

मैं इवेंट सोर्सिंग डिज़ाइन में आया था और मैं एक ऐसे एप्लिकेशन में उपयोग करना चाहूँगा जहाँ एक REST क्लाइंट की आवश्यकता हो (RESTful सटीक होना)। हालाँकि, मैं इन्हें एक साथ जोड़ने में विफल रहा क्योंकि REST काफी CRUD जैसा है और इवेंट सोर्सिंग कार्य आधारित है। मैं सोच रहा था कि आप REST सर्वर के अनुरोधों के आधार पर कमांड का निर्माण कैसे कर सकते हैं। इस उदाहरण पर विचार करें:

REST के साथ आप फ़ाइल नामक संसाधन के लिए एक नया राज्य रख सकते हैं। एक अनुरोध में आप नया फ़ाइल नाम भेज सकते हैं, आप मूल फ़ोल्डर और / या फ़ाइल के स्वामी को बदल सकते हैं और इसी तरह।

सर्वर का निर्माण कैसे करें ताकि मैं इवेंट सोर्सिंग का उपयोग कर सकूं। मैं इन संभावनाओं के बारे में सोच रहा था:

  1. सर्वर पर तय करें कि कौन क्षेत्रों बदल रहे थे और उचित आदेश (बनाने RenameFileCommand, MoveFileCommand, ChangeOwnerCommand, ...) और इन व्यक्तिगत रूप से प्रेषण। हालाँकि इस सेटअप में, प्रत्येक आदेश दूसरों को लेनदेन से बाहर करने में विफल हो सकता है और इस प्रकार संसाधन में "परमाणु" परिवर्तन से बाहर हो सकता है।

  2. डिस्पैच केवल एक आदेश ( UpdateFileCommand) और आदेश हैंडलर में, कुल में अधिक सटीक, जो निर्धारित क्षेत्रों बदल रहे थे और इसके बजाय अलग-अलग घटनाओं भेजने के लिए ( FileRenamedEvent, FileMovedEvent, OwnerChangedEvent, ...)

  3. यह एक मुझे बिल्कुल पसंद नहीं है: सर्वर के अनुरोध में मैं उन हेडर में निर्दिष्ट करूंगा जो उपयोग करने के लिए आदेश देते हैं, क्योंकि UI अभी भी कार्य आधारित है (लेकिन संचार REST के माध्यम से किया जाता है)। हालांकि यह REST संचार के किसी अन्य उपयोग (जैसे बाहरी ऐप्स में) में विफल हो जाएगा क्योंकि वे केवल एक अनुरोध में एक फ़ील्ड को बदलने के लिए बाध्य नहीं हैं। इसके अलावा मैं UI, REST और ES- आधारित बैकएंड में काफी बड़ी युग्मन लाता हूं।

आप किसे पसंद करेंगे या क्या इससे निपटने का कोई बेहतर तरीका है?

साइड नोट: इवेंट-सोर्सिंग के लिए जावा और एक्सॉन फ्रेमवर्क में लिखा गया ऐप।


निश्चित रूप से 3 नहीं। मैं 1 करूँगा, लेकिन मुझे इसके बारे में सोचना होगा।
inf3rno

क्या आप इस बारे में सवाल करते हैं कि क्या एक HTTP अनुरोध कई कमांड का परिणाम दे सकता है? क्या मैं अच्छी तरह से समझता हूं? IMHO। यह ऐसा करने में सक्षम होना चाहिए, लेकिन मैंने कुछ समय के लिए DDD के बारे में नहीं पढ़ा है, इसलिए मुझे इसे लागू करने के तरीके के बारे में एक नमूना कोड की जांच करनी होगी।
inf3rno

मुझे एक उदाहरण मिला, लेकिन यह सीआरयूडी है। github.com/szjani/predaddy-issuetracker-sample/blob/3.0/src/hu/… मैं लेखक से पूछूंगा कि उसकी क्या राय है, वह मुझसे ज्यादा DDD के बारे में जानता है।
inf3rno

1
मेरा यह है कि यदि आप तत्काल स्थिरता चाहते हैं, तो आपको "काम की इकाई" में कई कमांड का उपयोग करना चाहिए। यदि आप अंततः सुसंगतता के बारे में बात कर रहे हैं, तो सवाल मेरे लिए मायने नहीं रखता है। एक और संभव समाधान एक सम्मिश्र भेजने के लिए, जिसमें वे कमांड शामिल हो सकते हैं जिन्हें आप परमाणु निष्पादित करना चाहते हैं। यह एक सरल संग्रह हो सकता है, केवल एक चीज मायने रखती है कि बस इसे ठीक से संभाल सकती है।
inf3rno

1
उनके अनुसार आपको कमांड और HTTP अनुरोधों के बीच 1: 1 संबंध प्राप्त करने का प्रयास करना चाहिए। यदि आप ऐसा नहीं कर सकते (यह एक बुरी गंध है), तो आपको इसे परमाणु बनाने के लिए बल्क (मुझे इसे समग्र कहा जाता है) का उपयोग करना चाहिए।
inf3rno

जवाबों:


11

मुझे लगता है कि आपके पास यहां बेमेल को लागू करने के लिए एक उपयोगकर्ता-प्रक्रिया हो सकती है।

पहला: क्या कोई उपयोगकर्ता ईमानदारी से एक साथ एक फाइल में कई बदलाव करना चाहेगा ? एक नाम बदलना (जिसमें पथ का परिवर्तन शामिल हो सकता है या नहीं?), स्वामित्व का परिवर्तन, और शायद फ़ाइल सामग्री का परिवर्तन (तर्क के लिए) अलग-अलग कार्यों की तरह लगता है।

मामले को ले लो जहां जवाब "हाँ" है - आपके उपयोगकर्ता वास्तव में इन परिवर्तनों को एक साथ करना चाहते हैं।

उस मामले में, मैं दृढ़ता से किसी भी क्रियान्वयन कई घटनाओं भेजता है के खिलाफ की सलाह देते हैं - RenameFileCommand, MoveFileCommand, ChangeOwnerCommand- यह प्रतिनिधित्व करने के लिए एक उपयोगकर्ता के इरादे।

क्यों? क्योंकि घटनाएं विफल हो सकती हैं। शायद इसकी अत्यंत दुर्लभ, लेकिन आपके उपयोगकर्ता ने एक ऐसा ऑपरेशन प्रस्तुत किया जो परमाणु दिखे - यदि डाउनस्ट्रीम घटनाओं में से एक भी विफल हो जाता है, तो आपका एप्लिकेशन स्टेट अब अमान्य है।

आप एक संसाधन पर दौड़ के खतरों को भी आमंत्रित कर रहे हैं जो कि प्रत्येक घटना संचालकों के बीच स्पष्ट रूप से साझा किया गया है। आपको "ChangeOwnerCommand" इस तरह से लिखना होगा कि फ़ाइल का नाम और फ़ाइल पथ कोई फर्क नहीं पड़ता, क्योंकि वे उस समय तक तारीख से बाहर हो सकते हैं जब तक कमांड प्राप्त होती है।

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

मेरे कहने का मतलब यह है कि - क्या होगा यदि कोई व्यक्ति लगभग उसी समय फ़ाइल पर एक और ऑपरेशन करता है। 6 आदेश किसी भी क्रम में ढेर हो सकते हैं। यदि हमारे पास सिर्फ 2 परमाणु कमांड होते हैं, तो पहले वाली कमांड सफल हो सकती है और बाद की कमांड विफल हो सकती है "संसाधन को संशोधित किया गया है क्योंकि इसे अंतिम रूप से प्राप्त किया गया था"। लेकिन जब कमांड परमाणु नहीं होते हैं तो इसके खिलाफ कोई सुरक्षा नहीं है, इसलिए सिस्टम संगतता का उल्लंघन किया जाता है।

दिलचस्प बात यह है कि थॉटवर्क्स प्रौद्योगिकी रडार, जनवरी 2015 में अनुशंसित "रेस्ट विदाउट पीयूटी" नामक इवेंट आधारित आर्किटेक्चर जैसी किसी चीज़ के लिए एक आंदोलन है । यहाँ बिना PUT के आराम करने के बारे में काफी लंबा ब्लॉग है

अनिवार्य रूप से, विचार यह है कि POST, PUT, DELETE और GET छोटे अनुप्रयोगों के लिए ठीक हैं, लेकिन जब आपको यह सोचना शुरू करना होगा कि कैसे डाल और पोस्ट करें और हटाएं तो दूसरे छोर पर व्याख्या की जा सकती है, आप युग्मन का परिचय देते हैं। (उदाहरण के लिए "जब मैं अपने बैंक खाते से जुड़े संसाधन को हटाता हूं, तो खाता बंद कर दिया जाना चाहिए") और प्रस्तावित प्रस्ताव को रीस्ट को अधिक घटना वाले तरीके से व्यवहार करना है। यानी एक ही घटना संसाधन के रूप में उपयोगकर्ता के इरादे को पूरा करता है।

अन्य मामला सरल है। यदि आपके उपयोगकर्ता उन सभी कार्यों को एक साथ नहीं करना चाहते हैं, तो उन्हें न करें। प्रत्येक उपयोगकर्ता के इरादे के लिए एक घटना POST। अब आप अपने संसाधनों पर etag संस्करण का उपयोग कर सकते हैं।

अन्य अनुप्रयोगों के लिए जो आपके संसाधनों के लिए एक बहुत ही अलग एपीआई का उपयोग कर रहे हैं। जो परेशानी की तरह बदबू आ रही है। क्या आप अपने RESTful API के शीर्ष पर पुराने API का एक मुखौटा बना सकते हैं और उन्हें मुखौटा पर इंगित कर सकते हैं? यानी ऐसी सेवा को उजागर करें जो REST सर्वर के माध्यम से अनुक्रम में एक फ़ाइल में कई अपडेट करती है?

यदि आप पुराने समाधान के शीर्ष पर न तो RESTful इंटरफ़ेस का निर्माण करते हैं, और न ही REST समाधान के शीर्ष पर पुराने इंटरफ़ेस का एक पहलू बनाते हैं, और साझा डेटा संसाधन पर इंगित दोनों API को बनाए रखने का प्रयास करते हैं, तो आपको प्रमुख सिरदर्द का अनुभव होगा।


मैं बेमेल देख सकता हूं, हालांकि, REST द्वारा सिद्धांत रूप में, नए राज्य को संसाधन के लिए PUTting करके (कुछ प्रतिनिधित्व द्वारा) कई क्षेत्रों को अपडेट करना संभव है। यह कैसे होता है REST परिभाषा के अनुसार काम करता है - प्रतिनिधित्वात्मक राज्य हस्तांतरण, डाउन-साइड यह है कि उपयोगकर्ता का इरादा प्रक्रिया में खो जाता है। इसके अलावा, REST बाहरी API के लिए लगभग एक मानक है। मैं केवल ऐप डिज़ाइन करना चाहता हूं ताकि मैं दोनों का उपयोग कर सकूं। PUT को हटाना ES की वजह से वर्कअराउंड की तरह है। जब तक मैं देख सकता हूं, तब तक कई घटनाओं को छोड़ने वाला एक अपडेट कमांड एक लेन-देन में कमांड और इवेंट हैंडलिंग के रूप में उल्लेखनीय है।
लाल बालों वाली

Etag कुछ भी है मैं वैसे भी करना चाहूंगा। साथ ही आपका "लंबे ब्लॉग पोस्ट" का लिंक भी पहले लिंक जैसा ही है।
रेड इंडियन

अधिक विचार के साथ कुछ विचार के बाद मैं इस पर वापस आऊंगा। निश्चित रूप से, PUT को हटाना केवल "ES के लिए एक समाधान" नहीं है। मैंने ब्लॉग लिंक ठीक कर लिया है।
परफेक्शनिस्ट

4

बस अब मैं निम्नलिखित लेख में भाग गया, जो सामग्री-प्रकार हेडर में सर्वर के अनुरोध में कमांड नामों को निर्दिष्ट करने के लिए प्रोत्साहित करता है (जबकि मीडिया प्रकार के 5 स्तरों का पालन करते हुए)।

लेख में, वे उल्लेख करते हैं कि RPC- शैली REST के लिए खराब है और कमांड का नाम निर्दिष्ट करने के लिए सामग्री-प्रकार का विस्तार करने का सुझाव देते हैं:

एक सामान्य दृष्टिकोण RPC- शैली संसाधनों का उपयोग कर रहा है उदाहरण के लिए / api / InventoryItem / {id} / rename। जबकि यह प्रतीत होता है कि मनमानी क्रियाओं की आवश्यकता को दूर करता है, यह REST की संसाधन-उन्मुख प्रस्तुति के विरुद्ध है। हमें याद दिलाना होगा कि एक संसाधन एक संज्ञा है और HTTP क्रिया क्रिया / क्रिया और स्व-वर्णनात्मक संदेश (आरईएस के दस में से एक) जानकारी और इरादे के अन्य अक्षों को व्यक्त करने के लिए वाहन हैं। वास्तव में HTTP संदेश के पेलोड में कमांड किसी भी मनमाने कार्रवाई को व्यक्त करने के लिए पर्याप्त होना चाहिए। हालांकि, संदेश के शरीर पर निर्भर होने की अपनी समस्याएं हैं क्योंकि शरीर को आमतौर पर एक धारा के रूप में वितरित किया जाता है और कार्रवाई की पहचान करने से पहले शरीर को संपूर्णता में बफ़र करना हमेशा संभव नहीं होता है और न ही बुद्धिमान।

PUT /api/InventoryItem/4454c398-2fbb-4215-b986-fb7b54b62ac5 HTTP/1.1
Accept:application/json, text/plain, */*
Accept-Encoding:gzip,deflate,sdch
Content-Type:application/json;domain-model=RenameInventoryItemCommand`

लेख यहाँ है: http://www.infoq.com/articles/rest-api-on-cqrs

आप यहां मीडिया के 5 स्तरों के बारे में अधिक पढ़ सकते हैं: http://byterot.blogspot.co.uk/2012/12/5-levels-of-media-type-rest-csds.html


हालाँकि वे REST API के लिए डोमेन घटनाओं को उजागर कर रहे हैं, जिसे मैं एक बुरा अभ्यास मानूंगा, मुझे इसका समाधान पसंद है क्योंकि यह पूरी तरह से CQRS के लिए एक नया "प्रोटोकॉल" नहीं बनाता है, चाहे वह शरीर में या अतिरिक्त में कमांड नाम भेज रहा हो हेडर, और Restful सिद्धांतों के लिए सही रहता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.