लेन-देनात्मक इवेंट प्रकाशन और आउटबॉक्स
इवेंट प्रकाशन रजिस्ट्री और लेन-देनात्मक आउटबॉक्स पैटर्न से इवेंट वितरण सुनिश्चित कीजिए।
लेन-देनात्मक इवेंट प्रकाशन और आउटबॉक्स, CoddyKit पर Spring Boot 4 की संपूर्ण मार्गदर्शिका का एक निःशुल्क पाठ है। यह 4 में से 3वाँ पाठ है। इस अध्ययन पथ के 3 तक कोई भी पाठ पूरा पढ़ना निःशुल्क है — इसके बाद CoddyKit PRO हर पाठ अनलॉक करता है, साथ ही अंतर्निर्मित कोड संपादक और चौबीसों घंटे एआई शिक्षक के साथ व्यावहारिक अभ्यास भी उपलब्ध कराता है। यह Spring Boot 4 की संपूर्ण मार्गदर्शिका सीखने के मार्ग का हिस्सा है और आपकी प्रगति वेब तथा CoddyKit ऐप पर सिंक होती रहती है। Spring Boot 4 की संपूर्ण मार्गदर्शिका पाठ्यक्रम में कुल 4 पाठ शामिल हैं।
इवेंट क्यों खो जाते हैं
इवेंट-आधारित Spring Modulith एप्लिकेशन में मॉड्यूल एप्लिकेशन इवेंट प्रकाशित करके एक-दूसरे से संवाद करते हैं। कोई मॉड्यूल ट्रांज़ैक्शन के भीतर इवेंट उत्पन्न करता है और दूसरे मॉड्यूल के श्रोता उस पर प्रतिक्रिया देते हैं।
खतरा यह है कि डिफ़ॉल्ट रूप से, जब आप कोई इवेंट प्रकाशित करते हैं और कोई श्रोता उसे एसिंक्रोनस रूप से (या अलग ट्रांज़ैक्शन में) संसाधित करता है, तो प्रकाशक के कमिट हो जाने के बाद श्रोता का कार्य विफल हो सकता है। इसका परिणाम खोया हुआ इवेंट होता है — प्रकाशक की स्थिति बदल जाती है, लेकिन downstream साइड इफ़ेक्ट कभी नहीं होता।
- प्रकाशक एक
Orderको PAID स्थिति में कमिट करता है। - पुष्टि वाला ईमेल भेजने वाला एसिंक्रोनस श्रोता क्रैश हो जाता है।
- कोई पुनः प्रयास नहीं करता — ग्राहक को ईमेल कभी नहीं मिलता।
यह पाठ दिखाता है कि Spring Modulith की इवेंट प्रकाशन रजिस्ट्री डिलीवरी की गारंटी देने के लिए ट्रांज़ैक्शनल आउटबॉक्स पैटर्न लागू करती है।
ट्रांज़ैक्शनल आउटबॉक्स पैटर्न
ट्रांज़ैक्शनल आउटबॉक्स पैटर्न दोहरी-लेखन की समस्या हल करता है: आपको परमाणु रूप से (1) अपनी व्यावसायिक स्थिति बदलनी होती है और (2) यह दर्ज करना होता है कि कोई इवेंट डिलीवर किया जाना है।
एक ही ट्रांज़ैक्शन में डेटाबेस और संदेश ब्रोकर में लिखने का प्रयास करने के बजाय (वितरित ट्रांज़ैक्शन के बिना यह संभव नहीं है), आप उसी स्थानीय ट्रांज़ैक्शन में दोनों को एक ही डेटाबेस में लिखते हैं:
- व्यावसायिक बदलाव (जैसे ऑर्डर की पंक्ति)।
- आउटबॉक्स तालिका में इवेंट का विवरण देने वाली एक पंक्ति।
इसके बाद एक अलग प्रक्रिया असंसाधित आउटबॉक्स पंक्तियों को पढ़ती है, उन्हें डिलीवर करती है और हर एक को पूरा चिह्नित करती है। चूँकि आउटबॉक्स में लिखना व्यावसायिक ट्रांज़ैक्शन के साथ साझा होता है, इसलिए इवेंट तभी और केवल तभी दर्ज होता है जब व्यावसायिक बदलाव कमिट हुआ हो।
Spring Modulith की इवेंट प्रकाशन रजिस्ट्री
Spring Modulith पहले से तैयार आउटबॉक्स देता है: इवेंट प्रकाशन रजिस्ट्री। जब किसी इवेंट का ट्रांज़ैक्शनल श्रोता हो (जिस पर @ApplicationModuleListener लगा हो), तो Modulith अपने-आप:
- श्रोता के चलने से पहले एक इवेंट प्रकाशन पंक्ति लिखता है।
- श्रोता के सफलतापूर्वक पूरा होने पर उसे पूरा चिह्नित करता है।
- श्रोता द्वारा अपवाद उत्पन्न करने पर उसे अधूरा छोड़ देता है — ताकि पुनः प्रयास किया जा सके।
इसे सक्षम करने के लिए स्टार्टर और एक स्थायित्व मॉड्यूल जोड़ें। रजिस्ट्री प्रकाशनों को event_publication जैसी तालिका में स्थायी रूप से सहेजती है।
<dependency>
<groupId>org.springframework.modulith</groupId>
<artifactId>spring-modulith-starter-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.modulith</groupId>
<artifactId>spring-modulith-events-jpa</artifactId>
</dependency>@ApplicationModuleListener
मुख्य एनोटेशन @ApplicationModuleListener है। यह एक संयोजित एनोटेशन है, जो तीन व्यवहारों को मिलाता है:
@Async— श्रोता अलग थ्रेड पर चलता है और मॉड्यूल को अलग करता है।@Transactional(propagation = REQUIRES_NEW)— श्रोता अपने अलग ट्रांज़ैक्शन में चलता है।@TransactionalEventListener(phase = AFTER_COMMIT)— यह प्रकाशक का ट्रांज़ैक्शन कमिट होने के बाद ही सक्रिय होता है।
क्लासपाथ पर रजिस्ट्री होने पर, ऐसे श्रोता द्वारा सँभाले गए हर इवेंट के लिए एक आउटबॉक्स प्रविष्टि मिलती है। यदि श्रोता विफल होता है, तो प्रकाशन अधूरा रहता है और रीस्टार्ट के बाद भी मौजूद रहता है।
@Component
class OrderNotifications {
@ApplicationModuleListener
void on(OrderCompleted event) {
// runs async, in a NEW transaction, after the publisher committed
emailService.sendConfirmation(event.orderId());
}
}इवेंट प्रकाशित करना
प्रकाशन वाला पक्ष सरल रहता है। किसी सामान्य @Transactional सेवा विधि के भीतर आप ApplicationEventPublisher.publishEvent(...) को कॉल करते हैं। Spring Modulith इस प्रकाशन को इंटरसेप्ट करता है और, क्योंकि कोई ट्रांज़ैक्शनल मॉड्यूल श्रोता मौजूद है, आपके व्यावसायिक बदलाव के उसी ट्रांज़ैक्शन में आउटबॉक्स पंक्ति लिखता है।
इवेंट के लिए अपरिवर्तनीय Java रिकॉर्ड का उपयोग करें — ये संक्षिप्त, क्रमबद्ध किए जा सकने योग्य और स्पष्ट रूप से मान-आधारित होते हैं।
public record OrderCompleted(String orderId) {}
@Service
class OrderService {
private final OrderRepository orders;
private final ApplicationEventPublisher events;
OrderService(OrderRepository orders, ApplicationEventPublisher events) {
this.orders = orders;
this.events = events;
}
@Transactional
public void complete(String orderId) {
Order order = orders.findById(orderId).orElseThrow();
order.markCompleted(); // business change
events.publishEvent(new OrderCompleted(orderId)); // outbox row, same tx
}
}परमाण्विकता कैसे काम करती है
यह वह महत्वपूर्ण क्रम है जो डिलीवरी की गारंटी देता है:
- आपकी
complete()विधि एक ट्रांज़ैक्शन खोलती है और ऑर्डर में बदलाव करती है। publishEventModulith से उसी ट्रांज़ैक्शन में एक अधूरी event_publication पंक्ति INSERT करवाता है।- ट्रांज़ैक्शन कमिट होता है — ऑर्डर का बदलाव और आउटबॉक्स पंक्ति एक साथ, परमाणु रूप से दर्ज होते हैं।
- कमिट के बाद,
@ApplicationModuleListenerएक नए ट्रांज़ैक्शन में चलता है। - सफलता मिलने पर प्रकाशन को पूरा चिह्नित कर दिया जाता है।
यदि कमिट और श्रोता की सफलता के बीच JVM क्रैश हो जाए, तो पंक्ति डेटाबेस में अभी भी अधूरी रहती है और फिर से प्रकाशित किए जाने के लिए तैयार रहती है। कोई भी इवेंट चुपचाप नहीं खोता।
event_publication तालिका
JPA स्थायित्व मॉड्यूल प्रकाशनों को एक तालिका में सहेजता है। हर पंक्ति क्रमबद्ध किए गए इवेंट और उसके लक्षित श्रोता की पहचान करती है, साथ ही समय-मुहरें भी रखती है। स्कीमा को जानने से आपको पुनः प्रयास और निगरानी को समझने में सहायता मिलती है।
id— UUID प्राथमिक कुंजी।listener_id— वह पूर्णतः योग्य श्रोता विधि जिसे इसे सँभालना है।event_type+serialized_event— इवेंट पेलोड (डिफ़ॉल्ट रूप से Jackson के माध्यम से JSON)।publication_date— इसे बनाए जाने का समय।completion_date— अधूरा होने तक NULL; श्रोता के सफल होने पर इसका मान सेट किया जाता है।
completion_date IS NULL वाली पंक्ति ऐसा लंबित इवेंट है जिसकी डिलीवरी (या पुनः डिलीवरी) की प्रतीक्षा है।
CREATE TABLE event_publication (
id UUID NOT NULL,
listener_id TEXT NOT NULL,
event_type TEXT NOT NULL,
serialized_event TEXT NOT NULL,
publication_date TIMESTAMP WITH TIME ZONE NOT NULL,
completion_date TIMESTAMP WITH TIME ZONE,
PRIMARY KEY (id)
);स्टार्टअप पर फिर से प्रकाशन
अधूरे प्रकाशन तब तक बेकार हैं जब तक कोई उनका पुनः प्रयास न करे। Spring Modulith एप्लिकेशन स्टार्टअप पर लंबित इवेंट फिर से प्रकाशित कर सकता है, जिससे डिलीवरी के बीच हुए क्रैश से उबरा जा सकता है।
इसे application.properties में सक्षम करें:
spring.modulith.republish-outstanding-events-on-restart=true
बूट होने पर Modulith सभी अधूरी event_publication पंक्तियाँ पढ़ता है और उनके श्रोताओं को फिर से चलाता है। चूँकि श्रोताओं को इडेम्पोटेंट होना चाहिए, आंशिक रूप से संसाधित इवेंट को दोबारा चलाना सुरक्षित है।
# application.properties
spring.modulith.republish-outstanding-events-on-restart=true
# optional: also serialize events as JSON columns you can query
spring.modulith.events.jdbc.schema-initialization.enabled=trueइडेम्पोटेंट श्रोता
किसी इवेंट की डिलीवरी एक से अधिक बार हो सकती है (क्रैश के बाद पुनः प्रयास या निर्धारित पुनःप्रेषण के कारण), इसलिए कम-से-कम-एक-बार की गारंटी के लिए आपके श्रोताओं का इडेम्पोटेंट होना आवश्यक है। एक ही इवेंट को दो बार संसाधित करने पर वही अंतिम स्थिति मिलनी चाहिए जो उसे एक बार संसाधित करने पर मिलती है।
सामान्य तकनीकें:
- स्वाभाविक व्यावसायिक कुंजी (ऑर्डर आईडी) का उपयोग करें और जाँचें कि साइड इफ़ेक्ट पहले ही हो चुका है या नहीं।
- एक विशिष्ट बाधा वाली डुप्लिकेट-रोधक तालिका में संसाधित इवेंट आईडी दर्ज करें।
- ऑपरेशन को स्वाभाविक रूप से इडेम्पोटेंट बनाएँ (UPSERT, या वृद्धि करने के बजाय स्थिति को सीधे निर्धारित करना)।
@Component
class InventoryAdjuster {
private final ProcessedEventRepository processed;
@ApplicationModuleListener
void on(OrderCompleted event) {
// skip if we've already handled this exact event
if (!processed.markIfNew(event.orderId())) {
return;
}
inventory.release(event.orderId());
}
}अधूरे इवेंट का निर्धारित पुनःप्रेषण
स्टार्टअप पर पुनः प्रकाशन केवल रीस्टार्ट होने पर सहायता करता है। लंबे समय तक चलने वाली सेवाओं के लिए अटके हुए प्रकाशनों की समय-समय पर पुनर्प्राप्ति भी आवश्यक है (जैसे ऐसा श्रोता जिसने अस्थायी त्रुटि उत्पन्न की हो)। Modulith पूर्णता / पुनःप्रेषण शेड्यूलर उपलब्ध कराता है।
spring.modulith.events.completion-mode— यह नियंत्रित करता है कि पूर्ण पंक्तियों को हटाया जाए, संग्रहित किया जाए या अपडेट किया जाए।- नियत अंतराल पर पुनःप्रेषण सक्षम करें, ताकि किसी सीमा से अधिक पुरानी अधूरी घटनाओं पर अपने-आप फिर प्रयास हो।
इडेम्पोटेंसी के साथ मिलकर यह आउटबॉक्स को अलग संदेश ब्रोकर के बिना स्वयं-सुधार करने वाला डिलीवरी चैनल बना देता है।
# application.properties
spring.modulith.events.republish-outstanding-events-on-restart=true
spring.modulith.events.completion-mode=update
# resubmit publications still incomplete after this interval
spring.modulith.events.republish-outstanding-events.interval=PT10Mआउटबॉक्स से बाहरी ब्रोकर तक
यही रजिस्ट्री बाहरी संदेश-प्रणाली से भी जुड़ती है। Spring Modulith बाह्यीकरण मॉड्यूल (Kafka, RabbitMQ, AMQP, SQS आदि) उपलब्ध कराता है। आप किसी इवेंट पर @Externalized लगाते हैं और एक ट्रांज़ैक्शनल श्रोता उसे उसी आउटबॉक्स के आधार पर ब्रोकर को प्रकाशित करता है।
इसका अर्थ है कि कम-से-कम-एक-बार की गारंटी प्रक्रियाओं की सीमाओं के पार भी लागू होती है: ब्रोकर को भेजना स्वयं एक इवेंट प्रकाशन है, जिसे संदेश ब्रोकर द्वारा स्वीकार किए जाने के बाद ही पूरा चिह्नित किया जाता है।
import org.springframework.modulith.events.Externalized;
@Externalized("orders.completed::#{orderId()}")
public record OrderCompleted(String orderId) {}
// add: spring-modulith-events-kafka
// spring.modulith routes the event to topic "orders.completed"
// keyed by orderId, only after the publishing tx commitsत्वरित जाँच
ट्रांज़ैक्शनल आउटबॉक्स की गारंटी की अपनी समझ जाँचें।
पुनरावलोकन
आपने सीखा कि transactional outbox pattern का उपयोग करके Spring Modulith में event delivery की गारंटी कैसे दी जाती है:
- Event Publication Registry आपके business change के same transaction में एक
event_publicationrow को persist करता है — इससे dual-write समस्या हल हो जाती है। @ApplicationModuleListener= async + REQUIRES_NEW transaction + AFTER_COMMIT, इसलिए listeners publisher के commit करने के बाद चलते हैं और उन्हें अपनी outbox entry मिलती है।- Listener के सफल होने तक publication incomplete रहती है (
completion_date IS NULL); failures उसे retry के लिए छोड़ देते हैं। - Republish on restart और scheduled resubmission अटकी हुई events को पुनर्प्राप्त करते हैं — इससे delivery at-least-once हो जाती है।
- क्योंकि delivery at-least-once है, इसलिए listeners must be idempotent।
@Externalizedcross-process guarantees के लिए उसी outbox को Kafka/RabbitMQ/SQS से जोड़ता है।
एआई शिक्षक के साथ Java सीखें — निःशुल्क
अपने ब्राउज़र में वास्तविक कोड लिखें और चलाएँ, चौबीसों घंटे एआई शिक्षक से तुरंत सहायता पाएँ, और वेब या ऐप पर वहीं से शुरू करें जहाँ आपने छोड़ा था।
- पाठ्यक्रम
- 21
- पाठ
- 84
अक्सर पूछे जाने वाले प्रश्न
क्या “लेन-देनात्मक इवेंट प्रकाशन और आउटबॉक्स” पाठ निःशुल्क है?
हाँ — Spring Boot 4 की संपूर्ण मार्गदर्शिका अध्ययन पथ के 3 तक कोई भी पाठ, जिसमें “लेन-देनात्मक इवेंट प्रकाशन और आउटबॉक्स” भी शामिल है, यहाँ वेब पर पूरा पढ़ना निःशुल्क है। इसके बाद CoddyKit PRO हर पाठ अनलॉक करता है, साथ ही अंतर्निर्मित कोड संपादक और चौबीसों घंटे एआई शिक्षक के साथ इंटरैक्टिव अभ्यास भी उपलब्ध कराता है। Spring Boot 4 की संपूर्ण मार्गदर्शिका पाठ्यक्रम में कुल 4 पाठ शामिल हैं।
“लेन-देनात्मक इवेंट प्रकाशन और आउटबॉक्स” में मैं क्या सीखूँगा?
इवेंट प्रकाशन रजिस्ट्री और लेन-देनात्मक आउटबॉक्स पैटर्न से इवेंट वितरण सुनिश्चित कीजिए। आप ब्राउज़र में सीधे चलाए जाने वाले व्यावहारिक कोड के साथ Spring Boot 4 की संपूर्ण मार्गदर्शिका का अभ्यास करते हैं, और पाठ पूरा करते समय 24/7 एआई ट्यूटर आपके प्रश्नों के उत्तर देता है।
क्या Spring Boot 4 की संपूर्ण मार्गदर्शिका शुरू करने के लिए मुझे किसी अनुभव की आवश्यकता है?
पहले के अनुभव की आवश्यकता नहीं है। CoddyKit पर Spring Boot 4 की संपूर्ण मार्गदर्शिका शुरुआती से लेकर उन्नत शिक्षार्थियों तक सभी के लिए व्यवस्थित किया गया है, इसलिए आप यहीं से या शुरुआत से सीखना शुरू कर सकते हैं और अपनी गति से आगे बढ़ सकते हैं। यह 4 में से 3वाँ पाठ है।
“लेन-देनात्मक इवेंट प्रकाशन और आउटबॉक्स” पाठ पूरा करने में कितना समय लगता है?
CoddyKit का अधिकांश पाठ लगभग 5–10 मिनट में पूरा हो जाता है। हर पाठ छोटा और संवादात्मक है, इसलिए आप लगातार प्रगति करते हैं और वेब या ऐप पर वहीं से सीखना जारी रख सकते हैं जहाँ आपने छोड़ा था।
क्या मैं इस Spring Boot 4 की संपूर्ण मार्गदर्शिका पाठ में कोड लिख और चला सकता हूँ?
हाँ। हर Spring Boot 4 की संपूर्ण मार्गदर्शिका पाठ में एक अंतर्निर्मित कोड संपादक शामिल है, जिससे आप सीधे अपने ब्राउज़र में वास्तविक कोड लिख और चला सकते हैं और तुरंत एआई प्रतिक्रिया पा सकते हैं—स्थानीय सेटअप की आवश्यकता नहीं है।
इस पाठ्यक्रम के सभी पाठ
- ऐप्लिकेशन मॉड्यूल और सीमा सत्यापन
- आंतरिक ऐप्लिकेशन इवेंट और लिस्नर
- लेन-देनात्मक इवेंट प्रकाशन और आउटबॉक्स
- मॉड्यूल एकीकरण परीक्षण और परिदृश्य