PRODसंप्रभु यूरोपीय BaaS मंचडैशबोर्ड खोलें →

इंजीनियरिंग · 10 मिनट पढ़ा

बहु-सेवा Rust बैकएंड के लिए कार्गो कार्यस्थान

Affane Daylami · Fondateur · 12 अगस्त 2026

ब्लॉग पर वापस जाएँ

रस्ट में एक बहु-सेवा बैकएंड तुरंत एक ही प्रश्न उठाता है: प्रति सेवा एक डिपो, या एक कार्गो कार्यक्षेत्र? ऑराबेस ने दूसरे विकल्प का निर्णय लिया। ग्यारह सेवाएँ, एक सीएलआई, और पाँच साझा पुस्तकालय एक ही Cargo.toml रूट में रहते हैं, जिसमें सभी के लिए एक ही Cargo.lock होता है। यहां बताया गया है कि इस कार्यक्षेत्र का निर्माण कैसे किया जाता है, इसे पंक्ति दर पंक्ति पढ़ें।

यह अंग्रेजी पाठ फ़्रेंच मूल से स्वचालित रूप से उत्पन्न हुआ था और अभी तक इसकी समीक्षा नहीं की गई है।
यह पृष्ठ स्वचालित रूप से अनुवादित किया गया था. अंग्रेजी संस्करण प्रामाणिक है.

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

अनिवार्य है
  • ऑराबेस रूट कार्गो वर्कस्पेस 18 स्पष्ट सदस्यों की घोषणा करता है: 11 सेवाएँ, aura-cliCLI, 5 साझा libs और aurabase-rs SDK - resolver = "2" के अंतर्गत और एक Cargo.lock।
  • [workspace.dependencies] साझा संस्करणों को केंद्रीकृत करता है; प्रत्येक टोकरा अपनी स्वयं की संख्या निर्धारित करने के बजाय { workspace = true } के साथ विरासत में मिलता है - सिवाय इसके कि जब कोई टोकरा चुपचाप ओवरराइड हो जाता है।
  • services/ के अंतर्गत एक फ़ोल्डर स्वचालित रूप से कार्यक्षेत्र का सदस्य नहीं है: members सूची स्पष्ट है, ग्लोब नहीं, जो गैर-रस्ट कोड को बाहर करने में सक्षम है।
  • [profile.release] पूरे कार्यक्षेत्र पर केवल एक बार लागू होता है - panic = "unwind" जैसा विकल्प एक साथ सभी ग्यारह सेवाओं पर लागू होता है।
#
कार्यस्थल क्यों?

प्रति सेवा एक डिपो, या केवल एक Cargo.lock?

एक कार्यस्थान कार्गो एक एकल Cargo.lock और एक एकल लक्ष्य निर्देशिका के तहत कई क्रेटों को समूहित करता है - वही कार्यक्षमता जो रस्ट का पैकेज प्रबंधक इस मामले के लिए प्रदान करता है। ग्यारह अलग-अलग रस्ट बायनेरिज़, प्रत्येक अपने स्वयं के भंडार में, पहली नज़र में अधिक स्वतंत्र लगते हैं। व्यवहार में, इसका मतलब है ग्यारह अलग-अलग Cargo.lock, ग्यारह संस्करण रिज़ॉल्यूशन जो समय के साथ भिन्न हो सकते हैं, और कोई गारंटी नहीं है कि दो सेवाएँaxum या sqlxके एक ही संस्करण को संकलित करती हैं।

A Cargo workspace solves this at the package manager level, not the team discipline level. All members share a single Cargo.lock at the root: a common dependency is resolved once, to an identical version, for the entire graph. This is also what makes a cross-service refactor (changing a signature in aura-core, for example) visible to a single cargo build --workspace, rather than discovered service by service in production. This is one of the choices that distinguishes our 100% unified Rust core from a heterogeneous stack assembled service by service.

#
शरीर रचना

Cargo.toml रूट: रिज़ॉल्वर और सदस्य

यह सब घोषणा [workspace] और इसकी सूची membersसे शुरू होता है। ऑराबेस में, यह सूची services/*जैसे सामान्य पैटर्न द्वारा उत्पन्न होने के बजाय, हस्तलिखित है, भूमिका - सेवाओं, उपकरणों, libs द्वारा समूहीकृत है।

Cargo.tomltoml
[workspace]
resolver = "2"

members = [
    # सेवाएं
    "services/aura-gateway",
    "services/aura-auth",
    "services/aura-db",
    # … 8 अन्य सेवाएँ (आभा-वास्तविक समय, आभा-भंडारण, आभा-एआई,…)
    # औजार
    "aura-cli",
    # लिब्ज़
    "libs/aura-core",
    # …4 अन्य कार्य
    "aurabase-rs",
]

resolver = "2" कोई कॉस्मेटिक विवरण नहीं है. कार्गो का रिज़ॉल्वर v2 build-dependencies और लक्ष्य-विशिष्ट निर्भरता (उदाहरण के लिएtarget.'cfg(windows)') की कार्यक्षमता को बाकी ग्राफ़ से अलग करता है - वे अब अंतिम बाइनरी में लीक नहीं होते हैं। यह कार्यक्षेत्र के सभी सदस्यों के बीच समान निर्भरता के संस्करणों को भी एकीकृत करता है जो इसे साझा करते हैं: एक axum, केवल एक बार, ग्यारह स्वतंत्र संकल्प नहीं।

#
परंपरा

वर्कस्पेस.पैकेज: एक संस्करण, एक संस्करण, सिद्धांत रूप में साझा किया गया

[workspace.package] एक बार सामान्य फ़ील्ड - संस्करण, संस्करण, लेखक, लाइसेंस - घोषित करता है कि प्रत्येक टोकरा उन्हें कॉपी करने के बजाय version.workspace = true के साथ प्राप्त कर सकता है।

कार्गो.टोमल (रूट)toml
[workspace.package]
version = "0.1.1"
edition = "2021"

# Services/aura-gateway/Cargo.toml
[package]
name = "aura-gateway"
version.workspace = true

ऑराबेस की सभी ग्यारह सेवाएँ इसी पैटर्न का पालन करती हैं। दो क्रेट विचलन करते हैं, और यह इस लेख को तैयार करते समय पाई गई दो विसंगतियों में से पहली है: aura-cli हार्ड कॉपी में version = "0.2.0" घोषित करता है, और lib libs/aura-migrations version = "0.1.0" घोषित करता है - दोनों कार्यक्षेत्र के 0.1.1 से भिन्न हैं।

इसका क्या मतलब है

version.workspace = true वैकल्पिक है, फ़ील्ड दर फ़ील्ड, क्रेट दर क्रेट। कोई भी चीज किसी टोकरे को अपना नंबर रखने से नहीं रोकती - स्वेच्छा से (उदाहरण के लिए, अलग से प्रकाशित एक उपकरण) या भूल से। कार्यस्थान ऑडिट को इस फ़ील्ड को क्रेट दर क्रेट जांचना चाहिए, न कि वंशानुक्रम मानना ​​चाहिए।

#
डिडुप्लीकेशन

कार्यस्थान.निर्भरताएँ: सत्य का एक स्रोत, जब तक कि कोई टोकरा इसे दरकिनार न कर दे

[workspace.dependencies] कई क्रेट्स द्वारा साझा की गई निर्भरता को केंद्रीकृत करता है। प्रत्येक सेवा अपनी स्वयं की संस्करण बाधा निर्धारित करने के बजाय इसे { workspace = true } के साथ संदर्भित करती है।

कार्गो.टोमल (रूट)toml
[workspace.dependencies]
axum = { version = "0.8", features = ["ws", "multipart", "macros"] }
sqlx = { version = "0.8", default-features = false, features = […] }
tower_governor = { version = "0.8", features = ["axum"] }
governor = "0.10"

# Services/aura-gateway/Cargo.toml - कार्यक्षेत्र गवर्नर को इनहेरिट नहीं करता है
governor = "0.8"  # स्थानीय संस्करण, भिन्न

यह दूसरी वास्तविक विसंगति है: कार्यक्षेत्र 0.10संस्करण में governor को केंद्रीकृत करता है, लेकिन aura-gateway विरासत में मिलने के बजाय अपनी स्वयं की लाइन governor = "0.8" को पुनः घोषित करता है - गेटवे अपनी दर को नंगे governor क्रेट के साथ लागू करता है, जब aura-auth, aura-ai, aura-db और aura-functions मिडलवेयर में tower_governor से गुजरें। एक कार्यक्षेत्र विचलन को नहीं रोकता है: यह केवल इसे दृश्यमान बनाता है, अगर हम तुलना करने में परेशानी उठाते हैं।

हालाँकि, सभी निर्भरताएँ केंद्रीकृत होने के लायक नहीं हैं। wasmtime [workspace.dependencies]में कहीं भी दिखाई नहीं देता है: केवल एक टोकरा, aura-functions, इसे अपने WASM रनटाइम के लिए उपयोग करता है, इसलिए यह स्थानीय रूप से घोषित रहता है। हम जो नियम लागू करते हैं: दो या दो से अधिक क्रेट्स साझा करने के क्षण से ही कार्यस्थल स्तर पर निर्भरता बढ़ाएं, इससे पहले नहीं।

#
आंतरिक ग्राफ

libs/ से सेवाएँ/: जो किस पर निर्भर करता है

पाँच साझा कार्य (aura-core, aura-crypto, aura-db-adapters, aura-migrations, aura-telemetry) को [workspace.dependencies] - aura-core = { path = "libs/aura-core" } में पथ निर्भरता के रूप में घोषित किया जाता है - फिर प्रत्येक सेवा चुनती है कि उसे वास्तव में किनकी आवश्यकता है।

परिणामी ग्राफ़ एक फ़ाइल से दूसरी फ़ाइल में पढ़ने योग्य रहता है। aura-gateway केवल पांच आंतरिक कार्यों में से तीन पर निर्भर करता है - aura-core, aura-crypto और aura-telemetry। रूट करने के लिए पर्याप्त है, PostgREST साइडकार के लिए एक JWT पर हस्ताक्षर करें और aura-db-adapters और न ही aura-migrationsको छुए बिना, इसके निशान निर्यात करें। aura-provisioner``aura-migrationsजोड़ता है: यह एक प्रोजेक्ट के निर्माण के परिणामस्वरूप स्कीमा माइग्रेशन को दोबारा चलाता है।

सबसे संकीर्ण मामला aura-migratorहै, समर्पित बाइनरी जो सीआई/सीडी माइग्रेशन करता है। ऑराबेस के आंतरिक कार्यों में, इसके उत्पादन [dependencies] में केवलaura-migrations सूचीबद्ध है - aura-core केवल परीक्षण के लिए इसके [dev-dependencies]में दिखाई देता है। इसलिए उत्पादन के लिए वितरित बाइनरी में कोईaura-core कोड शामिल नहीं है; यह केवल cargo testके दौरान मौजूद रहता है।

#
ठोस मामला

एक टोकरा, कई बायनेरिज़: आभा-वास्तविक समय विभाजन

हर बार जब आप एक नई तैनाती योग्य प्रक्रिया चाहते हैं तो कार्यक्षेत्र को एक नया सदस्य बनाने की आवश्यकता नहीं होती है। aura-realtime कार्यक्षेत्र का एक एकल सदस्य बना हुआ है, लेकिन इसका Cargo.toml एक ही साझा [lib]के आसपास तीन अलग-अलग [[bin]] तालिकाओं की घोषणा करता है।

Cargo.tomltoml
[lib]
name = "aura_realtime"

[[bin]]
name = "aura-realtime"

[[bin]]
name = "aura-realtime-cdc-worker"
path = "src/bin/cdc_worker.rs"

[[bin]]
name = "aura-realtime-ws-front"
path = "src/bin/ws_front.rs"

घोषणापत्र स्वयं दोनों के बीच की सीमा का दस्तावेजीकरण करता है। cdc-worker पोलिंग द्वारा पोस्टग्रेज़ परिवर्तनों को कैप्चर करता है और पब/सब कोर (Client::publish_with_headers) में NATS पर प्रकाशित करता है, बिना वेबसॉकेट सर्वर खोले - जेटस्ट्रीम, इसी सेवा में, विशेष रूप से क्रॉस-इंस्टेंस उपस्थिति केवी की सेवा करता है, सीडीसी फैन-आउट की नहीं। ws-front केवल NATS का उपभोग करता है और WebSocket/SSE कनेक्शन रखता है, कभी भी CDC को छुए बिना - पूर्ण विवरण वास्तविक समय इंजन दस्तावेज़ में हैं। दोनों बायनेरिज़ [lib]के माध्यम से समान आरएलएस फ़िल्टरिंग कोड साझा करते हैं, लेकिन कुबेरनेट्स में स्वतंत्र रूप से तैनात और स्केल करते हैं। एक नए कार्यक्षेत्र सदस्य के बजाय एक क्रेट में कई बायनेरिज़ चुनने के लिए यह सही संकेत है: समान आंतरिक तर्क, विभिन्न परिनियोजन टोपोलॉजी।

#
बचने के लिए जाल

सेवाओं/ के अंतर्गत एक फ़ाइल आवश्यक रूप से कार्गो सदस्य नहीं है

aura-edge-runtime फ़ोल्डर ऑराबेस रिपॉजिटरी में मौजूद है। हालाँकि, इसमें कोई Cargo.toml नहीं है - केवल टाइपस्क्रिप्ट (index.ts, envelope.ts), और यह रूट वर्कस्पेस की members सूची में कहीं भी दिखाई नहीं देता है।

अस्टुसे

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

पाठ सामान्यीकरण करता है: services/ के सबफ़ोल्डर्स को सूचीबद्ध करके रस्ट बैकएंड की सेवाओं की गणना करने से एक गलत संख्या मिलती है। कार्यक्षेत्र में वास्तव में क्या संकलित होता है, इस पर केवल रूट Cargo.toml ही आधिकारिक है।

#
संकलन

[प्रोफ़ाइल.रिलीज़]: संपूर्ण कार्यक्षेत्र के लिए एक एकल सेटिंग

कार्यक्षेत्र के मूल में घोषित [profile.release] रिलीज़ मोड में संकलित सभी सदस्यों पर लागू होता है - समायोजित करने के लिए केवल एक स्थान, ग्यारह पर नहीं। कार्गो अपने संकलन प्रोफ़ाइल संदर्भमें सभी उपलब्ध कुंजियों का दस्तावेजीकरण करता है; ऑराबेस केवल पाँच को सक्रिय करता है।

कार्गो.टोमल (रूट)toml
[profile.release]
lto = "thin"          # एलटीओ क्रॉस-क्रेट, प्रदर्शन/निर्माण समय संतुलन
codegen-units = 1     # सर्वोत्तम समग्र इनलाइनिंग
panic = "unwind"   # टोकियो/एक्सम → 500 द्वारा अलग की गई घबराहट, वैश्विक दुर्घटना नहीं
strip = "symbols"
opt-level = 3

"abort" के बजाय panic = "unwind" का विकल्प सीधे फ़ाइल टिप्पणी में दर्ज किया गया है: एक एक्सम हैंडलर में घबराहट को टोकियो द्वारा इंटरसेप्ट किया जाता है, कार्य 500 लौटाता है, और प्रक्रिया अन्य समवर्ती अनुरोधों को पूरा करना जारी रखती है।abort का प्रदर्शन लाभ अंतर-क्वेरी अलगाव के नुकसान के लायक नहीं है।

#
व्यवहार में

टूलचेन और महत्वपूर्ण आदेशों को फ़्रीज़ करें

एक एकीकृत कार्यक्षेत्र निर्भरता संस्करण सेट करता है, लेकिन कंपाइलर का संस्करण नहीं। rust-toolchain.toml, मूल रूप से, रिपॉजिटरी में cargo या rustc पर किसी भी सीधी कॉल के लिए टूलचेन (channel = "1.93" आज) को फ्रीज कर देता है।

यह फ़ाइल सटीक रूप से मौजूद है क्योंकि एक मूक बहाव हुआ: एक सीआई कार्रवाई ने दिन के stable चैनल को rust-toolchain.tomlको पढ़े बिना स्थापित किया, जबकि रिलीज डॉकर छवि जमे हुए संस्करण के साथ संकलित हुई। एक कमिट आज के स्थिर रस्ट के साथ सभी परीक्षण पास कर सकता है, फिर छवि निर्माण में सफलता प्राप्त कर सकता है - मर्ज के बाद खोजा गया, पहले नहीं। rustupकिसी भी प्रत्यक्ष कमांड के लिए इस फ़ाइल का सम्मान करता है: सीआई वर्कफ़्लो को प्रभावित किए बिना, यह एकमात्र आवश्यक फिक्स था।

terminalbash
# संपूर्ण कार्यक्षेत्र संकलित करें
cargo build --workspace

# एक एकल क्रेट का परीक्षण करें (संपूर्ण कार्यस्थान का नहीं)
cargo test -p aura-auth

# संपूर्ण कार्यक्षेत्र पर सख्त प्रतिबंध, चेतावनियाँ = त्रुटियाँ
cargo clippy --workspace --all-targets -- -D warnings

# का प्रारूपण
cargo fmt --all

एक आखिरी विवरण, उन लोगों के लिए जो इसे निष्पादित करने से पहले मैनिफ़ेस्ट पढ़ते हैं: aura-cli क्रेट एक बाइनरी संकलित करता है जिसकी तालिका [[bin]] इसे aurabaseनाम देती है, न कि aura। प्रकाशित एनपीएम रैपर, @aurabase/cli, दो कमांड्स को उजागर करता है - aura और aurabase दोनों एक ही स्क्रिप्ट की ओर इशारा करते हैं। [[bin]] कार्गो का नाम, टोकरे का नाम, और एनपीएम रैपर द्वारा उजागर किया गया नाम तीन अलग-अलग चीजें हैं; अन्य दो में से किसी का भी अनुमान नहीं लगाया जा सकता।

#
संक्षिप्त

चेकलिस्ट: कहां क्या घोषित करना है

हर बार जब आप कार्गो कार्यक्षेत्र में एक टोकरा जोड़ते हैं तो पाँच निर्णय सामने आते हैं। ऊपर दिए गए ऑराबेस उदाहरण के आधार पर, यहां प्रत्येक को घोषित किया गया है।

सदस्यों की सूची[कार्यक्षेत्र] सदस्यरूट - स्पष्ट सूची, कभी ग्लोब नहीं
साझा संस्करण/संस्करण[कार्यस्थान.पैकेज]रूट - संस्करण.वर्कस्पेस = सत्य, क्रेट द्वारा, वैकल्पिक
निर्भरता 2+ क्रेट्स द्वारा साझा की गई[कार्यक्षेत्र.निर्भरताएं]रूट - फिर प्रत्येक टोकरे में {कार्यस्थान = सत्य}
एकल उपभोक्ता पर निर्भरता[निर्भरताएँ] टोकरे कीस्थानीय स्तर पर, कार्यक्षेत्र से गुजरे बिना
प्रोफ़ाइल बनाएं[प्रोफ़ाइल.रिलीज़]केवल रूट - सभी सदस्यों पर लागू होता है

किसी मौजूदा कार्गो कार्यक्षेत्र का ऑडिट करने के लिए - आपका या उस प्रोजेक्ट का जिसे आप संभाल रहे हैं - ऊपर दर्ज की गई विसंगतियों के प्रकार का पता लगाने के लिए चार जांचें पर्याप्त हैं:

  1. प्रत्येक टोकरे के [workspace.package].version की version से तुलना करें - एक अलग मान आवश्यक रूप से एक बग नहीं है, लेकिन दस्तावेजीकरण के लायक है।
  2. प्रत्येक टोकरे द्वारा स्थानीय रूप से घोषित निर्भरता के साथ [workspace.dependencies] की तुलना करें - विभिन्न संस्करणों के साथ दोनों तरफ मौजूद नामों को देखें।
  3. रूट Cargo.toml में members सूची की तुलना रिपॉजिटरी में वास्तविक सबफ़ोल्डर्स से करें - members से गायब फ़ोल्डर आवश्यक रूप से एक चूक नहीं है।
  4. यह मानने के बजाय कि यह क्रेट नाम या संभावित एनपीएम रैपर द्वारा उजागर नाम से मेल खाता है, प्रत्येक संकलित बाइनरी ([[bin]] name) के वास्तविक नाम की जांच करें।

तैनाती के लिए तैयार हैं?

पाँच मिनट में आपका बैकएंड।

किसी क्रेडिट कार्ड की आवश्यकता नहीं · 500 एमबी निःशुल्क · 50,000 एमएयू