pg_durable - PostgreSQL के लिए durable SQL functions
(github.com/microsoft)- PostgreSQL के भीतर retry, scheduling, parallel fan-out, conditional branching को एक छोटे SQL DSL से संभालने वाला durable function extension
- container या external service के बिना, केवल Postgres और background worker से काम करता है
- हर step PostgreSQL में state को checkpoint के रूप में लिखता है, इसलिए crash, restart, या connection टूटने पर भी रुके हुए बिंदु से फिर शुरू होता है
- queue management, state tracking, crash recovery, step coordination, retry को खुद implement करने की ज़रूरत नहीं; सिर्फ SQL लिखें, orchestration engine बाकी संभालता है
- सीधे implement करने पर 300+ lines of boilerplate लगने वाले काम को एक DSL call से बदलता है, और PostgreSQL 17 पर open source के रूप में तुरंत इस्तेमाल किया जा सकता है
अवलोकन और मुख्य मूल्य
- Postgres में built-in crash-proof durable function जो retry, scheduling, parallel fan-out, और conditional branching को छोटे SQL DSL से orchestrate करता है
- अतिरिक्त infrastructure के बिना केवल Postgres + background worker से चलता है; अलग container या external service की ज़रूरत नहीं
- queue management, state tracking, crash recovery, step coordination, और retry सब संभालने वाला orchestration engine, उपयोगकर्ता को सिर्फ SQL लिखना होता है
pg_durable के बिना implement करने पर
- 3 aggregations को parallel में चलाकर dashboard refresh करना हो, और उसमें retry व crash recovery भी जोड़नी हो, तो 300+ lines of boilerplate चाहिए
- जिन्हें खुद बनाना पड़ेगा: queue setup और configuration, worker management और polling, message processing और state tracking, error handling और retry, manual step coordination
- उदाहरण code में
job_queue,job_results,job_state,workflow_steps,step_variables,scheduled_jobsजैसी कई state tables, polling worker, workflow progression, crash recovery, parallel execution coordinator, variable passing, scheduling, और cleanup functions शामिल हैं - scheduling के
next_runcalculation के लिए अतिरिक्त external cron parser library भी चाहिए
pg_durable के साथ implement करने पर
- वही parallel aggregation + dashboard refresh एक ही
df.start()call में व्यक्त किया जा सकता है,&operator से fan-out और~>से join- उदाहरण: 3 queries parallel branches में चलने के बाद
refresh dashboardstep पर मिलती हैं और result बनाती हैं - live execution example में 3-step parallel execution के बाद join → dashboard ready तक सिर्फ 1.9 सेकंड में durable तरीके से पूरा
- उदाहरण: 3 queries parallel branches में चलने के बाद
- queue management, state tracking, crash recovery, step coordination, और retry सब pg_durable संभालता है
प्रमुख विशेषताएँ
-
Durable by default
- हर step PostgreSQL में state को checkpoint के रूप में लिखता है, इसलिए crash, restart, या connection टूटने पर भी workflow जीवित रहता है
- जहां रुका था, ठीक वहीं से फिर शुरू होता है
-
Automatic retries
- flaky tasks के लिए built-in retry logic, step fail होने पर सिर्फ वही step retry होता है और बाकी workflow चलता रहता है
- manual error-handling code की ज़रूरत नहीं
-
Full observability in SQL
- सभी workflow states Postgres tables में store होते हैं; execution history देखना, step output जांचना, और failures debug करना standard SQL से संभव
- external dashboard की ज़रूरत नहीं
-
Parallel execution
&operator याdf.join()से independent tasks को fan-out किया जा सकता है, और aggregation, API calls, ETL steps को automatic coordination के साथ साथ-साथ चलाया जा सकता है
कौन-कौन से pattern बनाए जा सकते हैं
-
ETL Pipelines
- cleanup → transform → load को क्रमबद्ध guarantee के साथ जोड़ना; हर step पिछले step का इंतज़ार करता है और failure पर pipeline साफ़ तरीके से रुकती है (
~> sequence,|=> variables)
- cleanup → transform → load को क्रमबद्ध guarantee के साथ जोड़ना; हर step पिछले step का इंतज़ार करता है और failure पर pipeline साफ़ तरीके से रुकती है (
-
Parallel Aggregation
- user count aggregation + revenue sum + inventory check को एक साथ चलाना; कई queries में fan-out करके सबके पूरा होने का इंतज़ार (
&,df.join())
- user count aggregation + revenue sum + inventory check को एक साथ चलाना; कई queries में fan-out करके सबके पूरा होने का इंतज़ार (
-
Order Processing
- order ID capture करके validation, processing, और completion steps तक भेजना; steps के बीच variables अपने आप flow होते हैं (
|=> capture,$var substitution,df.sleep())
- order ID capture करके validation, processing, और completion steps तक भेजना; steps के बीच variables अपने आप flow होते हैं (
-
Scheduled Jobs
- cron schedule पर API polling, record archiving, और data sync; loop स्थायी रूप से चलता है और restart के बाद भी जीवित रहता है (
@> loop,df.wait_for_schedule())
- cron schedule पर API polling, record archiving, और data sync; loop स्थायी रूप से चलता है और restart के बाद भी जीवित रहता है (
-
Conditional Branching
- pending work, row count, या flags देखकर process या skip branch चुनना; branching logic application में नहीं, SQL में रहती है (
df.if(),?> conditional)
- pending work, row count, या flags देखकर process या skip branch चुनना; branching logic application में नहीं, SQL में रहती है (
-
Multi-step Validation
- data fetch → schema validation → business rule checks → approve/reject; हर step checkpoint होता है, इसलिए failure पर भी progress नहीं खोती
-
Database Maintenance
- autovacuum blockers, table bloat, और wraparound risk detect करके review के लिए दिखाना; approval का इंतज़ार करने के बाद restart के बावजूद durable तरीके से correction (
?> conditional,df.wait_for_signal(),@> loop)
- autovacuum blockers, table bloat, और wraparound risk detect करके review के लिए दिखाना; approval का इंतज़ार करने के बाद restart के बावजूद durable तरीके से correction (
-
Azure Functions & HTTP
df.http()से Azure Functions या allowed HTTPS endpoints को SQL से सीधे call करना; document chunking, row enrichment, और record classification inline संभालना
-
Human-in-the-Loop Approval
- सामान्य काम अपने आप approve करना और high-risk कामों (बड़े invoices, destructive operations) को मानवीय approval signal आने तक pause करना (
df.wait_for_signal(),df.if())
- सामान्य काम अपने आप approve करना और high-risk कामों (बड़े invoices, destructive operations) को मानवीय approval signal आने तक pause करना (
AI-आधारित authoring support
- workflow को plain English में describe करने पर Copilot सही durable-function SQL generate कर सकता है; syntax सीखे बिना सिर्फ अपनी जरूरत बतानी होती है
- repository में reusable agent skill
pg-durable-sqlशामिल है, जो GitHub Copilot और अन्य agents को operators, variable substitution, loop, parallel join आदि के साथ सही SQL generate करना सिखाती है
Open source उपलब्धता
- waitlist या lock-in के बिना पूरी तरह open source; repository clone और build करके अपने PostgreSQL पर तुरंत चलाया जा सकता है
- laptop, server, या cloud कहीं भी durable orchestration लागू किया जा सकता है
Azure HorizonDB managed option
- Azure HorizonDB Microsoft की नई PostgreSQL cloud service है, जिसमें pg_durable built-in है, इसलिए लिखे गए durable functions को ज्यों का त्यों रखते हुए enterprise scale, security, और AI जोड़ा जा सकता है
- अधिकतम 3× तेज performance, storage auto-scale होकर 128 TB तक, compute scale-out होकर 3,072 vCore तक
- Microsoft Defender से real-time threat detection, Microsoft Entra ID से identity management
- Filtered DiskANN vector search, semantic ranking, और in-database AI model curation
- Microsoft Fabric near-real-time mirroring, VS Code integration, और GitHub Copilot integration
-
Built-in AI pipelines
- HorizonDB, pg_durable के durable execution के ऊपर managed end-to-end AI pipelines की layer जोड़ता है; हर step checkpointed, retried, और crash-safe होता है
- step flow: Ingest (documents/data load) → Chunk (content split) → Embed (vectorization) → Index (DiskANN storage) → Serve (search/ranking)
1 टिप्पणियां
Hacker News की राय
लगता है 2026 Postgres queues का साल होगा: DBOS[0], pgQue[1] जैसी दिशा दिखाई दे रही है, और कम्युनिटी का ऐसे विकल्प बनाना बढ़िया है
लेकिन एक पूर्व application engineer के नज़रिए से, मैं queue logic को code और Git के अंदर रखना पसंद करता हूँ। सही tools मिलें तो शायद राय बदल जाए
[0]: https://www.dbos.dev/
[1]: https://github.com/NikolayS/pgque
version control, debugging, testing, release कैसे होते हैं, यह जानने की जिज्ञासा है। data locality और stack simplification के लिए सब कुछ एक जगह रखना अच्छा लगता है, लेकिन ऐसा भी महसूस होता है कि इसे “ठीक से” करने के उपयोगी ज्ञान का बहुत हिस्सा खो जाता है
Supabase में थोड़ा भी जटिल काम करने के लिए Postgres functions बनानी पड़ती थीं, यह बात भी इसी कारण बेहद नापसंद थी। हालांकि पिछली startup में हमने Postgres के ऊपर एक simple job queue खुद बनाया था, और अगर pgQue जैसा कुछ होता तो शायद वह कहीं अधिक polished रूप लेता
multi-master extensions भी ऐसी चीज़ नहीं हैं जिन्हें तुरंत इस्तेमाल कर लें और पूरी तरह सुरक्षित मान लें, इसलिए database scaling की ज़रूरत को जल्दी सामने ला देने वाले write-heavy complex work को उसमें डालने में हिचक है
local setup के समय triggers local database में चले जाएँ, इसके लिए उन्हें Django migrations में ठूँसने के मामले भी थे
इसमें stored procedures वाली गंध आती है। unit testing भी कठिन, version control भी कठिन, और business logic database के अंदर छिपकर एक “hidden brain” बन जाता है
noisy workloads को isolate करना भी मुश्किल है, observability भी नहीं है, और scaling pressure पूरा का पूरा Postgres पर आ जाता है। खासकर API calls जैसी input/output की कमी है। जो काम सिर्फ local database के अंदर चलते हैं, उनके लिए ठीक हो सकता है, लेकिन उपयोग-क्षेत्र संकरा लगता है
बेशक database upgrade procedure ठीक होना चाहिए। अगर team members root से मनमानी SQL migrations चलाते फिरें, तो फिर परेशानी तय है
unit testing भी दूसरी SQL testing की तरह ही की जा सकती है, बस database चलाना पड़ता है। अगर stored procedures को test नहीं कर सकते, तो इसका मतलब SQL को ही test करने का तरीका नहीं है, और असली समस्या वही है
stored procedures का विकल्प यह नहीं है कि business logic database में बिल्कुल न हो, बल्कि अक्सर उसका मतलब यह होता है कि SQL codebase में इधर-उधर बिखरा रहता है, test करना कठिन होता है, versioning और encapsulation खराब होते हैं, और प्रदर्शन बेवजह धीमा हो जाता है
observability वाली बात कुछ हद तक सही है; SQL की समस्याओं के अंदर झाँकना ज़्यादातर programming languages की तुलना में अधिक मेहनत माँगता है। लेकिन अगर stored procedures input/output और scaling problems पैदा कर रहे हैं, तो उन्हें गलत तरह इस्तेमाल किया जा रहा है; सही इस्तेमाल में वे अक्सर input/output को काफ़ी घटाकर scalability सुधारते हैं
अगर मैंने सही समझा है, तो Pi LLM harness के developers द्वारा बनाया गया Absurd pure database access को जितना हो सके उतना कम करने की दिशा में लगता है। मैं अभी इस विषय को बस देखना शुरू ही कर रहा हूँ
https://github.com/earendil-works/absurd
बेशक मुझे सारी अंदरूनी बातें नहीं पता, इसलिए सचमुच जिज्ञासा है
“कब इस्तेमाल नहीं करना चाहिए” में लिखा है, “जब workflow का अधिकांश हिस्सा Postgres के बाहर हो और कई heterogeneous systems में फैला हो”; अगर ऐसा है, तो फिर समझ नहीं आता कि यह project Temporal जैसी चीज़ों से कैसे तुलना कर सकता है
लगता है शायद मैं इस recommendation से संकेतित limitation को गलत समझ रहा हूँ
तकनीकी रूप से यह दिलचस्प उपलब्धि हो सकती है, लेकिन इस तरह का SQL पढ़ना काफ़ी अजीब लगता है
SELECT df.start(@> (($$SELECT ... FROM demo.invoices WHERE status = 'pending'$$ |=> 'inv')~> df.if_rows('inv',$$UPDATE ... SET status = 'processing'$$~> (df.http(...) |=> 'resp')~> df.if($$SELECT $r.ok$$,-- classify, branch, wait for signal ...),df.sleep(5))),'invoice-approval-pipeline');कंपनी Azure से बंधी हुई है, और हम अब भी इंतज़ार कर रहे हैं कि Azure PostgreSQL आधुनिक फीचर्स की बराबरी करे
उदाहरण के लिए, यह इस्तेमाल नहीं कर सकते: https://www.paradedb.com/blog/hybrid-search-in-postgresql-th...
अल्ट्रा-वाइड हाई-डायमेंशनल वेक्टर का भी सपोर्ट नहीं है। pg_durable को open source करना अच्छी बात है, लेकिन पहले वे बुनियादी फीचर्स ही जोड़ लें जो AWS में सामान्य रूप से मिल जाते हैं
साफ़-साफ़ बताऊँ तो मैं pg_textsearch का maintainer हूँ और अभी Azure में हूँ। वेक्टर सपोर्ट वाली बात पूरी तरह समझ नहीं आई; क्या आपका मतलब Azure में उपलब्ध pgvector + diskann से आगे किसी और चीज़ से है?
hybrid search (BM25 + vector) के मामले में ParadeDB का pg_search भी AWS का native फीचर नहीं है; उसे EC2 पर खुद host करना पड़ता है। Azure PostgreSQL के लिए हमने pg_textsearch को native बनाया है, जो वही BM25 ranking model देता है, और उसका मुख्य contributor अभी Azure Postgres टीम में है
दस्तावेज़: https://learn.microsoft.com/en-us/azure/horizondb/ai/full-te...
हाई-डायमेंशनल वेक्टर के मामले में तो हम आगे हैं। HNSW इस्तेमाल करने वाला pgvector 2,000 dimensions तक सीमित है, लेकिन Azure वेक्टर स्टोरेज और सर्च के लिए pgvector को सपोर्ट करता है, और हाई-डायमेंशन, बड़े पैमाने के workloads के लिए Microsoft का graph-based vector index pg_diskann भी देता है। यह अधिकतम 16,000 dimensions तक सपोर्ट करता है, और graph traversal के दौरान WHERE conditions को evaluate करने वाला advanced in-index filtering भी देता है, जिससे selective conditions में recall कम नहीं होता
pgvector: https://learn.microsoft.com/en-us/azure/horizondb/ai/vector-...
DiskANN हाई-डायमेंशन सपोर्ट: https://learn.microsoft.com/en-us/azure/horizondb/ai/vector-...
ये फीचर्स अभी Azure PostgreSQL, खासकर Azure HorizonDB Preview में उपलब्ध हैं। अगर कोई खास workload है, तो हम उसे और विस्तार से देख सकते हैं
यह मुझे Apache Airflow जैसे DAG schedulers द्वारा बहुत पहले से हल की जा चुकी एक पुरानी समस्या का गलत समाधान लगता है
यह अजीब लगता है कि control flow को code की बजाय database में क्यों रखना चाहेंगे। मैं प्रोजेक्ट को नीचा नहीं दिखा रहा, बस अभी तक बात पूरी तरह समझ नहीं आई
यह प्रोजेक्ट ज़्यादा database-specific use case जैसा लगता है। इसका फायदा शायद यह है कि workflow logs और codebase को मिलाकर लाइन-दर-लाइन trace किए बिना, काम की सटीक state सीधे database में track की जा सकती है। लोड और latency भी कम हो सकते हैं, और operations के लिहाज़ से चलाने वाले components भी एक कम हो जाते हैं
[1] https://learn.microsoft.com/en-us/azure/durable-task/common/...
इसके उलट, यह तरीका अभी शायद ऐसा काम नहीं करता, लेकिन इसमें round-trip latency की लागत के बिना लगभग real-time performance feedback लेकर खुद को adjust करने की क्षमता हो सकती है
दस्तावेज़ और उदाहरण पढ़ने के बाद भी कुछ बातें स्पष्ट नहीं हैं। यह जानना चाहता हूँ कि
df.wait_for_schedule()कैसे काम करता हैअगर इसे application से कॉल करें तो क्या यह idempotent है, यानी एक ही parameter के साथ दो बार चलाने पर tick दो बार होता है, या इसे query console से केवल एक बार मैन्युअली कॉल किया जाता है, या migration script के हिस्से के रूप में चलाया जाता है, यह समझ नहीं आ रहा
यह भी जानना चाहता हूँ कि उदाहरण[0] में
timed_outtimeout होने पर लौटाया जाने वाला fixed constant है या नहीं। error या exception handling कैसे होती है, यह भी तुरंत साफ़ नहीं दिखता[0] https://github.com/microsoft/pg_durable/blob/main/examples/i...
df.start()को कॉल करने पर एक durable function बनती है और साथ ही उसका execution शुरू हो जाता है। यह कॉल उस execution को दर्शाने वाला instance ID लौटाती है, जिसे बाद में उस execution को refer करने के लिए इस्तेमाल किया जा सकता हैइस durable function के भीतर
df.wait_for_signal()को कॉल किया जाता है, और यह कॉल उस function instance के भीतर ठीक एक बार ही execute होती है, इसलिए duplicate संभव नहीं है। अगरdf.start()कॉल खुद timeout होकर फिर से चलाई जाती है तो duplicate हो सकता है, लेकिन उस स्थिति में एक अलग function instance बनता हैSQL execution के दौरान अगर कोई unhandled error आती है तो function instance fail हो जाता है, और state में वही सटीक error ऊपर आ जाती है
database के बाहर मौजूद orchestration tool की जगह इसे क्यों इस्तेमाल करना चाहिए, क्या कोई यह समझा सकता है। README और उदाहरण पढ़ने के बाद भी अभी तक बात पूरी तरह समझ नहीं आई
उसी data store से जुड़े दूसरे component के साथ backup को sync करने की ज़रूरत नहीं पड़ती, इसलिए यह ETL pipeline या state machine जैसे कामों के लिए अच्छा है। अगर ETL ज़्यादातर SQL में है, तो असली काम का उसी server पर चलना भी मददगार होता है
जब सारी state एक ही database में हो, तो consistent backup मिलने की संभावना भी ज़्यादा होती है
https://transport.data.gouv.fr पर Postgres का इस्तेमाल ऐसे ही काम के लिए किया जा रहा है, और काफ़ी processing करने वाली Elixir app में यह मददगार है। मुझे अभी pg_durable के बारे में ज़्यादा नहीं पता, लेकिन मैंने मिलते-जुलते समाधान इस्तेमाल या लागू किए हैं, इसलिए बात समझ में आती है
क्या database पहले से ही scale करना सबसे कठिन infra में से एक नहीं है। फिर उसके ऊपर long-running task और क्यों डालना चाहेंगे, यह समझ नहीं आता
आख़िरकार इस तरह का workload database के against ही चलने वाला काम है, चाहे उसे कोई external component trigger करे या न करे। data या AI pipeline में अतिरिक्त component से होने वाले round-trip और failure point से बचने के लिए database से HTTP query भेजने का तरीका भी अब ज़्यादा आम हो गया है। हालाँकि computation को data के पास लाना है या data को computation के पास ले जाना है, यह अब भी एक बड़ा architectural decision है
यह मुझे एक और https://en.wikipedia.org/wiki/Inner-platform_effect जैसा लगता है, जिसकी शायद ज़रूरत ही न पड़ती अगर लोकप्रिय programming language या virtual machine पहले से determinism, मापने योग्य और नियंत्रित step-by-step execution, runtime state को pause करना, serialization·deserialization और resume को support करतीं