प्रौद्योगिकी

हमने AI के साथ Omnilude के एकल बैकएंड को MSA में कैसे बदला

AAnonymous
12 मिनट पढ़ें

शुरुआत

यह लेख Omnilude बनाने के लिए हम ऐसा बैकएंड बना रहे हैं का अगला भाग है। पिछले लेख में मैंने Omnilude बैकएंड की मौजूदा संरचना और जिम्मेदारी की सीमाओं को एक ही प्रोडक्ट बैकएंड की तरह समझाया था। इस बार मैं बताना चाहता हूँ कि वही संरचना वास्तव में एक बड़े प्रोजेक्ट से कई सर्विस सीमाओं में कैसे बँटनी शुरू हुई।

MSA की चर्चा अक्सर ज़रूरत से ज़्यादा अमूर्त लगती है। यह कहना आसान है कि सिस्टम को बाँट दिया गया, अब स्वतंत्र deployment संभव है, या boundaries साफ़ हो गई हैं। लेकिन किसी चल रहे प्रोजेक्ट के अंदर वास्तव में क्या बदला, यह समझना उतना आसान नहीं होता.

Omnilude का बैकएंड इस बदलाव को समझाने के लिए काफ़ी ठोस उदाहरण देता है। आज यह auth-service, backbone-service, storage-service, ai-service, game-service, blog-service, और legacy-service जैसे हिस्सों में बँटा है, लेकिन इसकी शुरुआत ऐसी नहीं हुई थी। शुरू में यह एक बड़ा Spring Boot backend था।

इस लेख में मैं समझाऊँगा कि वह एकल प्रोजेक्ट क्यों टूटना शुरू हुआ, jspring(common) को पहले क्यों निकाला गया, legacy-service को जानबूझकर क्यों छोड़ा गया, और इस पूरी transition में AI ने वास्तव में क्या भूमिका निभाई।

शुरुआत में यह बस एक बड़ा backend था

Transition से पहले Omnilude का backend सीधी भाषा में कहें तो एक ऐसी जगह था जहाँ बहुत सी चीज़ें एक ही प्रोजेक्ट में भरी हुई थीं। Authentication भी वहीं था, AI भी, game logic भी, file storage भी, real-time events भी, और common utilities भी.

ऐसी संरचना शुरुआत में सुविधाजनक लगती है। Features जल्दी जुड़ते हैं और सब कुछ एक ही codebase में बदल सकता है। लेकिन जैसे-जैसे प्रोजेक्ट बड़ा होता है, समस्याएँ दिखने लगती हैं।

  • Authentication जैसी चीज़ें जिन्हें बहुत सावधानी से संभालना पड़ता है
  • AI जैसी चीज़ें जो बार-बार बदलती हैं और experiment माँगती हैं
  • Real-time events जैसी चीज़ें जहाँ stability बहुत महत्वपूर्ण है
  • Game domain जैसी चीज़ें जहाँ business logic तेज़ी से बढ़ती है

आख़िर में इन सब पर एक ही deployment pressure पड़ने लगता है।

इसे ऐसे समझ सकते हैं जैसे एक ही अलमारी में मौसमी कपड़े, gym wear, formal suits, blankets और toolbox सब रख दिए जाएँ। शुरुआत में यह ठीक लगता है। लेकिन एक समय के बाद एक चीज़ बदलना भी भारी लगने लगता है।

फिर इसे बाँटने की ज़रूरत क्यों पड़ी?

मैंने शुरुआत से ही MSA को अपने आप में लक्ष्य बनाकर काम शुरू नहीं किया था। वजहें कहीं ज़्यादा व्यावहारिक थीं।

सबसे बड़ी वजह यह थी कि मैं उन features को सामान्य deployments के प्रभाव से अलग रखना चाहता था जिन्हें लंबे समय तक connections बनाए रखने पड़ते हैं। Omnilude में backbone-service जैसी जगहें थीं जो WebSocket, SSE, event streams और long-running async work के बहुत करीब थीं। अगर unrelated domain changes की वजह से ऐसे हिस्से भी हिल जाते, तो operational impact तुरंत महसूस होता। Blog या game feature का change अगर connection-sensitive services को भी restart करा दे, तो ऐसी संरचना लंबे समय तक टिकाऊ नहीं होती।

दूसरी वजह deployment time थी। एक छोटा सा change भी पूरे बड़े app को build करने, image बनाने और फिर से deploy करने जैसा बन जाता था। प्रोजेक्ट जितना बड़ा होता गया, यह समय उतना ही ज़्यादा बेकार लगने लगा। अगर जल्दी बदलने वाले हिस्से एक ही deployment unit में बँधे रहें, तो पूरा सिस्टम साथ में धीमा हो जाता है।

उसके बाद responsibility boundaries का धुंधला होना भी बड़ी समस्या बन गया। Authentication rules, common exceptions, internal HTTP, messaging और file storage जैसी चीज़ें पूरे codebase में फैली हुई थीं। इससे यह समझना मुश्किल होता गया कि क्या common है और क्या domain-specific logic है।

एक और बड़ी वजह भी थी। मुझे काफ़ी स्पष्ट था कि आगे क्या बनाना है। Omnilude में मैं AI features बढ़ाना चाहता था, game services को आगे ले जाना चाहता था, और blog व tools जैसे अलग products भी जोड़ते रहना चाहता था। सब कुछ एक ही backend के अंदर बढ़ाते रहना एक समय के बाद अच्छा विकल्प नहीं लगा।

दूसरे शब्दों में, यह transition इसलिए नहीं हुई कि MSA अच्छा दिखता है। यह ज़्यादा उस restructuring जैसी थी जो connection-sensitive services को बचाने, deployment time घटाने और आगे के ideas को आगे बढ़ाते रहने के लिए ज़रूरी थी।

पहला कदम services को काटना नहीं, common rules को बाहर निकालना था

यहाँ एक महत्वपूर्ण बात है। इस transition का पहला कदम auth-service या ai-service को अलग करना नहीं था। उससे पहले मैंने common बनाया।

यह हिस्सा बहुत महत्वपूर्ण है। बाहर से service split domain split जैसा दिखता है, लेकिन व्यवहार में सबसे पहले यह पहचानना पड़ता है कि shared contract क्या है, और उसे बाहर निकालना पड़ता है।

Omnilude में यह भूमिका common ने निभाई।

  • Common exception handling
  • JWT conventions
  • Shared DTOs
  • Web-layer utilities
  • JPA और data access foundations
  • Internal HTTP और messaging helpers

इन चीज़ों को पहले common में रखने के बाद, आगे services को बाँटने पर भी वे एक-दूसरे से असंबंधित apps नहीं बने, बल्कि एक ही भाषा बोलने वाली संरचना बने रहे।

इसे ऐसे समझिए जैसे किसी इमारत को अलग-अलग कमरों में बाँटने से पहले सब जगह के power sockets और door handles का standard तय कर लिया जाए। अगर यह पहले नहीं किया गया, तो कमरे बाँट देने से जीवन आसान नहीं होता।

यह split हैरान करने वाली तेजी से हुआ

Repository history देखें तो transition बहुत कम समय में आगे बढ़ी। 18 जनवरी 2026 से 22 जनवरी 2026 के बीच मुख्य ढाँचा लगभग तैयार हो गया था।

सरल रूप में flow ऐसा था।

  • common extract करना
  • auth-service अलग करना
  • backbone-service अलग करना
  • storage-service अलग करना
  • ai-service को अलग करना शुरू करना
  • बचे हुए हिस्सों को legacy-service में isolate करना
  • game-service extract करना
  • उसके बाद blog-service को नए service की तरह रखना
  • Jenkins और Kubernetes को selective deployment के हिसाब से व्यवस्थित करना

इस क्रम के पीछे अपनी logic थी।

auth-service की boundaries अपेक्षाकृत साफ़ थीं। Authentication, accounts और permissions दूसरे services की shared dependency थे, इसलिए इसे पहले अलग करना बाकी संरचना के लिए reference point बन गया।

backbone-service infrastructure के ज़्यादा करीब था, क्योंकि यह real-time events, messaging और DTE जैसी capabilities से जुड़ा था। तेज़ी से बदलने वाली product logic से इसे अलग रखना operational रूप से बेहतर था।

storage-service का काम file storage के shared contract को संभालना था। File handling को एक जगह केंद्रित करने से blog, game और AI-generated outputs एक ही flow का हिस्सा बन सकते थे।

इसके बाद ai-service आया। यह हिस्सा बड़ा था, dependencies भी अधिक थीं, इसलिए मुश्किल था। लेकिन यह वही क्षेत्र था जहाँ सबसे ज़्यादा experimentation होना था, इसलिए इसे independent service के रूप में देखना सही लगा।

legacy-service को क्यों छोड़ा गया?

जब लोग MSA transition की कल्पना करते हैं, तो वे अक्सर एक साफ़ अंत सोचते हैं जहाँ monolith एक ही बार में गायब हो जाता है। व्यवहार में ऐसा अंत उतना यथार्थवादी नहीं होता।

इसीलिए Omnilude ने उन domains को legacy-service में रखा जो अभी पूरी तरह अलग नहीं किए गए थे।

यह फैसला पीछे हटना नहीं था। यह ज़्यादा एक buffer बनाने जैसा था।

legacy-service ने कई चीज़ें संभव बनाईं।

  • अधूरी migrations को ज़बरदस्ती तोड़ना नहीं पड़ा
  • नए और पुराने services एक ही product में साथ रह सके
  • system operable रहते हुए split जारी रहा
  • कठिन domains को बाद के लिए छोड़कर आसान हिस्से पहले निकाले जा सके

मेरे लिए यही किसी वास्तविक MSA transition का सबसे व्यावहारिक हिस्सा है। वास्तविक transition perfect split से कम और operable boundaries बनाने से ज़्यादा जुड़ी होती है।

उसके बाद game, blog और AI और साफ़ दिखने लगे

इसके बाद product-oriented services की पहचान और स्पष्ट होने लगी।

ai-service सिर्फ़ chatbot API नहीं है। इसके अंदर agent execution, workflows, generation pipelines, media generation, roleplay systems और product agents जैसी ज़िम्मेदारियाँ हैं। इस स्तर पर इसे independent service मानना ज़्यादा स्वाभाविक है।

game-service उस दिशा के सबसे करीब था जिसे मैं Omnilude में अंततः सबसे अधिक बढ़ाना चाहता था। Story quiz, scenarios और asset studio features जुड़ते-जुड़ते यह AI, storage और authentication को साथ बाँधने वाला domain-centered service बन गया।

blog-service थोड़ा अलग है। यह मूल monolith से सीधे काटा गया domain नहीं था। यह ज़्यादा उस service जैसा था जिसने पहले से अलग की गई architecture के ऊपर अपनी जगह बनाई। Deployment और shared rules पहले से अलग थे, इसलिए blog को शुरुआत से ही independent service की तरह design और operate किया जा सका।

इसलिए यह MSA transition सिर्फ़ पुराने हिस्सों को तोड़ने की कहानी नहीं थी। यह आगे बनने वाले नए products के लिए बेहतर units तैयार करने की बुनियाद भी थी।

असली बदलाव deployment में महसूस हुआ

सिर्फ़ code देखकर कोई project split हुआ हुआ लग सकता है। लेकिन MSA असल में तब वास्तविक लगती है जब deployment structure बदलती है।

Omnilude में यह बात Jenkinsfile, Jenkinsfile.prd और kubernetes/services/** में दर्ज है।

इस समय Jenkins इन सात services को selective deployment के रूप में संभाल सकता है।

  • auth-service
  • backbone-service
  • storage-service
  • ai-service
  • game-service
  • blog-service
  • legacy-service

इसका मतलब यह है कि repository अब भी एक ही repository हो सकती है, लेकिन यह अब एक ऐसा app नहीं रहा जिसे हर बार पूरा का पूरा deploy करना पड़े। यह ऐसी संरचना बन गई जिसमें ज़रूरत के हिसाब से सिर्फ़ वही service release की जा सकती है।

Kubernetes भी उसी दिशा में चलता है। हर service का अपना Deployment और Service है, और Ingress api.omnilude.com या dev-api.omnilude.com के नीचे path prefix के आधार पर routing करता है।

यही बिंदु महत्वपूर्ण है। MSA folders बाँटने का नाम नहीं है, बल्कि operating units बाँटने का नाम है। Omnilude में इस रेखा को पार करने के बाद ही मुझे लगा कि split सचमुच वास्तविक हो गया है।

आखिर में सबसे महत्वपूर्ण चीज़ service count नहीं थी

ऐसी transition के बाद ध्यान अक्सर इस पर जाता है कि कितनी services बनीं। पीछे मुड़कर देखने पर लगता है कि संख्या असली बात नहीं थी।

असल में ये चार सवाल अधिक महत्वपूर्ण थे।

  • क्या हमने shared rules को पहले बाहर निकाला ताकि आगे का split संभव हो सके?
  • क्या हमने तेज़ी से बदलने वाले domains और धीमे infrastructure concerns के बीच फर्क किया?
  • क्या हमने imperfect होने पर भी operable boundaries बनाई?
  • क्या हमने code split को वास्तविक deployment split से जोड़ा?

इन सवालों के आधार पर देखें तो Omnilude की transition मुझे काफ़ी व्यावहारिक लगती है। यह दुनिया का सबसे सुंदर diagram न हो, फिर भी इसने अगला product और अगला experiment संभालने लायक संरचना तैयार कर दी।

समापन

Omnilude backend की यह MSA transition किसी बड़े strategy document से शुरू हुई कहानी कम थी, और उस structural cleanup जैसी ज़्यादा थी जिससे होकर बड़े काम की ओर बढ़ने के लिए कभी न कभी गुजरना ही पड़ता है।

यह एक बड़े project से शुरू हुई, common को बाहर निकाला, auth, backbone, storage, ai, game और blog को अलग किया, बाकी हिस्सों को legacy-service में रखा, और आखिर में Jenkins तथा Kubernetes के साथ वास्तविक deployment units को align किया।

मेरे लिए यह पूरी प्रक्रिया बहुत Omnilude जैसी लगती है। Omnilude नाम में omni- की व्यापकता भी है और -lude का खेल वाला भाव भी। इसका अर्थ यह है कि कई functions और services हमेशा बिखरे रहने के लिए नहीं हैं, बल्कि अंततः एक बड़े play experience में मिल जाने के लिए हैं। इस अर्थ में यह transition नाम से भी मेल खाती है: मंज़िल साफ़ थी, इसलिए संरचना भी उसी के अनुसार बदलती रही।

अगले लेख में मैं architecture की बात से एक कदम आगे जाकर यह बताना चाहता हूँ कि हम वास्तव में game को कैसे implement कर रहे हैं।