Duurzame functies met pg_durable voor Azure HorizonDB (preview)

pg_durable is de duurzame uitvoeringsengine binnen Azure HorizonDB. Hiermee kunt u langlopende SQL-werkstromen (pijplijnen insluiten, ETL-taken, AI-aanroepen, geplande taken, goedkeuringsstromen) definiëren en uitvoeren met dezelfde betrouwbaarheidsgaranties die u zou verwachten van een toegewezen orchestrator zoals Durable Functions, zonder Postgres te verlaten.

pg_durable is ook de uitvoeringslaag onder duurzame AI-pijplijnen. Als u AI-pijplijnen gebruikt, pg_durable zorgt ervoor dat ze crashes overleven, het na een fout opnieuw proberen en worden hervat vanaf de laatst voltooide stap.

Note

pg_durable is in preview.

Wat 'duurzaam' betekent

Een duurzame functie in pg_durable wordt bij elke stap op schijf opgeslagen. Dat geeft u een specifieke set garanties die u niet krijgt van een gewoon BEGIN ... COMMIT blok of een cron-taak:

  • Overleeft het vastlopen en opnieuw opstarten van de database. Voltooide stappen worden niet opnieuw uitgevoerd wanneer de server terugkomt. Lopende stappen worden hervat vanaf het laatste controlepunt. Stappen in behandeling worden uitgevoerd wanneer de worker weer online komt.
  • Overleeft lange wachttijden. Een werkstroom kan uren in slaapstand staan, wachten op een cron-schema of blokkeren op een extern signaal en nog steeds verder gaan waar het was gebleven.
  • Bestand tegen storingen. Mislukte stappen kunnen automatisch opnieuw worden geprobeerd zonder de hele functie opnieuw uit te voeren.
  • Legt de identiteit vast. Een functie wordt uitgevoerd met de bevoegdheden van de gebruiker die deze heeft gestart, niet de bevoegdheden van de achtergrondwerker. Multitenant-workloads blijven geïsoleerd.
  • Blijft waarneembaar vanuit SQL. U kunt de status, geschiedenis, het aantal uitvoeringen en uitvoer controleren via dezelfde interface die u gebruikt voor alles in HorizonDB: een SELECT instructie.

Wat duurzame uitvoering niet automatisch doet: het maakt niet-idempotente externe bewerkingen niet uit zichzelf veilig om opnieuw te proberen. Als een stap een externe API aanroept die geld in rekening brengt, ontwerpt u de stap om idempotent te zijn (bijvoorbeeld door een idempotentiesleutel door te geven).

Wanneer gebruikt u pg_durable

Gebruik pg_durable dit wanneer u dat moet doen:

  • Het duurt zo lang dat het halverwege kan misgaan (het genereren van embeddings voor miljoenen rijen, een ETL-taak met meerdere stappen, een terugvulactie).
  • Moet opnieuw worden geprobeerd bij fouten zonder dat de onderdelen die al zijn geslaagd, opnieuw worden uitgevoerd.
  • Moet volgens een schema worden uitgevoerd (elk uur, elke weekdag om 9:00 uur).
  • Moet wachten op een externe gebeurtenis (een goedkeuring, een webhook, een signaal van een ander systeem).
  • Coördineert meerdere stappen met vertakkingen, samenvoegen of een wedloop.
  • Wordt momenteel geïmplementeerd als een externe orchestrator + een Postgres-database, waarbij het grootste deel van het werk het databaseonderdeel is.

Als uw werklast uit één korte transactionele instructie bestaat, hebt u pg_durable niet nodig. Gebruik een gewone INSERT / UPDATE.

Hoe werkt het?

Een duurzame functie is een grafiek van stappen die u bouwt met een SQL DSL en verzendt met df.start(). De grafiek blijft behouden en vervolgens wordt deze uitgevoerd door een achtergrondmedewerker.

Twee belangrijke ideeën:

  • Functiegrafiek en uitvoeringsstatus worden opgeslagen in HorizonDB zelf, in de df en duroxide schema's. Back-ups, point-in-time-herstel en hoge beschikbaarheid worden allemaal automatisch toegepast op de status van uw workflow. Er is geen afzonderlijke orchestratorstatus die moet worden beheerd.
  • De achtergrondmedewerker wordt gestart door shared_preload_libraries. De extensie wordt gedetecteerd na CREATE EXTENSION en begint met het uitvoeren van functies. Als de database opnieuw wordt opgestart, maakt de worker opnieuw verbinding met actieve instanties en hervat ze.

Note

De uitvoeringsengine binnen pg_durable is gebouwd op Duroxide, Microsofts opensource-runtime voor duurzame uitvoering voor Rust (geïnspireerd op het Durable Task Framework en Temporal). De duroxide schemanaam weerspiegelt dit: daar slaat Duroxide de orchestratiegeschiedenis, correlatie-id's en replaystatus op. De garanties voor deterministische replay, gecorreleerde gebeurtenis-ID's en duurzame timers die u van pg_durable krijgt, komen rechtstreeks van Duroxide.

Pg_durable inschakelen

Als u pg_durable wilt inschakelen in Azure HorizonDB, configureert u eerst een parametergroep en maakt u vervolgens de extensie in elke database.

Gebruik deze installatieartikelen:

  1. Maak een parametergroep voor uw server.
  2. Stel shared_preload_libraries zodanig in dat pg_durable wordt opgenomen.
  3. Stel azure.extensions zodanig in dat pg_durable wordt opgenomen.
  4. Pas de parametergroep toe op de server.
  5. Maak verbinding met elke doeldatabase en voer het volgende uit:

Maak de extensie in elke database waarin u deze wilt gebruiken:

CREATE EXTENSION IF NOT EXISTS pg_durable;

CREATE EXTENSION richt het df schema (functiegrafieken en bewakingsweergaven) en het duroxide schema (uitvoeringsstatus) in. De achtergrondmedewerker detecteert de extensie binnen een paar seconden en is klaar om functies uit te voeren.

Uw eerste duurzame functie

-- Start a one-step durable function
SELECT df.start('SELECT ''Hello, durable world!''');
-- Returns an 8-character instance ID, for example: a1b2c3d4

-- Check status
SELECT df.status('a1b2c3d4');

-- Get the result
SELECT df.result('a1b2c3d4');

Zelfs een eenstapsfunctie is duurzaam: als de database opnieuw wordt gestart na df.start() en voordat de worker de functie oppikt, wordt de functie nog steeds uitgevoerd.

Note

df.start() verzendt een werkstroom asynchroon en retourneert onmiddellijk. Gebruik voor workflows met meerdere stappen df.list_instances(), df.instance_info(), df.status() of df.result() om de voltooiing te bevestigen voordat u neveneffecten valideert.

Programmamodel

Een duurzame functie is een grafiek die is gebouwd op basis van stappen, operators en ingebouwde functies. Gewone SQL-tekenreeksen worden automatisch uitgepakt, dus u hoeft niet expliciet aan te roepen df.sql() .

Bedieners

Operator Meaning Example
~> Sequentie - eerst links uitvoeren, dan rechts 'SELECT 1' ~> 'SELECT 2'
& Join - parallel uitvoeren, op alles wachten 'SELECT 1' & 'SELECT 2'
| Race - parallel uitvoeren, de eerste wint fast_query | df.sleep(30)
?> !> If / else - vertakken op basis van een booleaanse voorwaarde cond ?> then_branch !> else_branch
@> Lus - herhaal oneindig (voorvoegseloperator) @> body
|=> Naam : het resultaat van een stap vastleggen 'SELECT id FROM users LIMIT 1' |=> 'user_id'

Nuttige ingebouwde functionaliteit

Functie Purpose
df.sleep(seconds) Pauzeer gedurende N seconden. Duurzaam bij opnieuw opstarten.
df.wait_for_schedule(cron) Wacht tot de volgende keer dat een cron-expressie overeenkomt.
df.wait_for_signal(name, timeout) Blokkeer totdat een externe df.signal() binnenkomt.
df.http(url, method, body, headers, timeout) Maak een HTTP-aanroep als een duurzame activiteit, met een nieuwe poging bij tijdelijke fouten.
df.if(cond, then, else) Voorwaardelijke vertakking.
df.loop(body, cond) Herhaal dit terwijl een SQL-voorwaarde waarheid is.
df.join(a, b) / df.race(a, b) Parallelle uitvoering en raceuitvoering.
df.join3(a, b, c) Voor parallelle uitvoering in drie richtingen.
df.start(body, label, database) Dien een Durable Function in en geef de instantie-id ervan terug.
df.cancel(id, reason) Annuleer een actief exemplaar.
df.status(id) / df.result(id) Controleer het resultaat.
df.explain(input) Geef de functiegrafiek weer voor visualisatie.

Lees meer over alle pg_durable functies.

Variabelen

|=> legt het resultaat van een stap vast met een naam; latere stappen verwijzen ernaar als $name.

SELECT df.start(
    'SELECT 100 AS amount' |=> 'total'
    ~> 'SELECT $total * 2 AS doubled'
);

Voorbeelden van gebruik

ETL in meerdere stappen met herpogingen

Een dagelijkse ETL die opschoont, laadt, indexeert en logt:

SELECT df.start(
    'DELETE FROM target WHERE loaded_at < now() - INTERVAL ''1 day'''
    ~> 'INSERT INTO target SELECT * FROM staging'
    ~> 'REINDEX TABLE target'
    ~> 'INSERT INTO etl_log (job, finished_at) VALUES (''nightly'', now())',
    'nightly-etl'
);

Als de database herstart tussen de DELETE en de INSERT, wordt de worker hervat vanaf de INSERT - de DELETE wordt niet opnieuw uitgevoerd.

Geplande taak (cron)

Voer elke weekdag om 9:00 uur een onderhoudstaak uit:

SELECT df.start(
    @> (
        df.wait_for_schedule('0 9 * * 1-5')
        ~> 'CALL refresh_materialized_views()'
    ),
    'weekday-refresh'
);

Als u deze taak wilt stoppen, kunt u de cancel functie uitvoeren.

SELECT df.cancel('a1b2c3d4', 'stop test cron job');

Goedkeuringswerkstroom met time-out

Wacht maximaal 24 uur op een extern goedkeuringssignaal en bevestig of wijs af:

SELECT df.start(
    'SELECT order_id, total FROM orders WHERE id = 1' |=> 'order'
    ~> df.wait_for_signal('approval', 86400) |=> 'sig'
    ~> df.if(
        'SELECT NOT ($sig::jsonb->>''timed_out'')::boolean
            AND ($sig::jsonb->''data''->>''approved'')::boolean',
        'UPDATE orders SET status = ''approved'' WHERE id = $order_id',
        'UPDATE orders SET status = ''rejected'' WHERE id = $order_id'
    ),
    'order-approval'
);

-- Later, approve from anywhere
SELECT df.signal('a1b2c3d4', 'approval',
                 '{"approved": true, "approver": "jane@contoso.com"}');

Duurzame HTTP-aanroep

df.http() maakt externe aanroepen als duurzame activiteiten: 5xx-antwoorden, netwerkfouten en time-outs worden automatisch opnieuw geprobeerd.

SELECT df.start(
    df.http('https://api.example.com/users/123', 'GET') |=> 'user'
    ~> 'INSERT INTO users_cache (data) VALUES (($user::jsonb->>''body'')::jsonb)',
    'fetch-user'
);

Lees meer over toegestane HTTP-beveiliging in pg_durable.

Bekijken en bedienen

Alles kan worden opvraagbaar vanuit SQL. Er is geen aparte gebruikersinterface of dienst die u hoeft te leren kennen.

-- All instances
SELECT * FROM df.list_instances();

-- Filter by status
SELECT * FROM df.list_instances() WHERE status = 'Running';
SELECT * FROM df.list_instances() WHERE status = 'Failed';

-- Detail for one instance
SELECT * FROM df.instance_info('a1b2c3d4');

-- Execution history (useful for retried or looped functions)
SELECT * FROM df.instance_executions('a1b2c3d4', 20);

-- The function graph as it ran
SELECT * FROM df.instance_nodes('a1b2c3d4');

-- System-wide metrics
SELECT * FROM df.metrics();

Controleren of de worker actief is:

SELECT epoch_id, last_seen_at, now() - last_seen_at AS time_since_last_heartbeat
FROM df._worker_epoch;

Een time_since_last_heartbeat korter dan 15 seconden betekent dat de worker gezond is. Alles wat groter is, of als er helemaal geen rijen zijn, betekent dat de worker niet beschikbaar is of nog niet is geïnitialiseerd.

Werkstromen in Visual Studio Code bewaken

De PostgreSQL-extensie voor Visual Studio Code bevat een tabblad Werkstromen in de weergave Pijplijnen en werkstromen, waar u pg_durable werkstroominstanties kunt inspecteren en de uitvoeringsstatus vanuit uw editor kunt controleren.

Het deelvenster Werkstromen openen

  1. Open de PostgreSQL-extensie in Visual Studio Code.
  2. Klik in Objectverkenner met de rechtermuisknop op de database.
  3. Selecteer Pijplijnen en werkstromen.
  4. Selecteer het tabblad Werkstromen .

In het linkerdeelvenster worden PG Durable Runs weergegeven en in het middelste deelvenster worden details van de geselecteerde werkstroominstantie weergegeven.

Schermopname van het tabblad Werkstromen in de PostgreSQL-extensie voor Visual Studio Code met pg Durable Runs en werkstroomdetails.

Workflowuitvoeringen bekijken

Wanneer u een werkstroomuitvoering selecteert, controleert u de samenvatting om het volgende te valideren:

  • Status: completed, running, of failed.
  • Run ID: Unieke id voor het exemplaar.
  • Gestarte tijd en duur: de voortgang en prestaties van de uitvoering bijhouden.
  • Detailvenster: Aanvullende metagegevens voor uitvoering.

Gebruik de beschikbare tabbladen om dieper in te gaan:

  • Grafiek: Visuele stapsgewijze uitvoeringsweergave met de werkstroomstructuur en stapstroom.
  • Timing: Weergave gericht op de duur voor prestatieanalyse en het identificeren van knelpunten.
  • Resultaten: Uitvoer- en resultaatgeoriënteerde details van de uitvoering van de werkstroom.

Voor werkstromen met betrekking tot AI-pijplijnen kunt u met een actie pijplijndefinitie weergeven (indien beschikbaar) een koppeling maken vanuit een werkstroomuitvoering naar de pijplijndefinitie, handig voor het vergelijken van gedrag bij uitvoeringen of het onderzoeken van regressies.

Identiteit en isolatie

Durable Functions worden uitgevoerd met de machtigingen van de gebruiker die ze heeft ingediend, niet met de machtigingen van de worker. pg_durable legt zowel session_user als current_user vast bij het indienen, dus functies die binnen een SET ROLE-context worden ingediend, worden uitgevoerd met die effectieve rol.

Dit betekent:

  • Gebruikers kunnen alleen gegevens zien en wijzigen waarvoor ze al toegangsrechten hebben.
  • Niet-supergebruikers kunnen bevoegdheden niet escaleren door een duurzame functie in te dienen.
  • Multitenant-workloads blijven geïsoleerd zolang uw rol en toekenningsmodel juist zijn.

Interactie met replica's, back-ups en PITR

  • Back-up en PITR. Functiegrafiek (df schema) en uitvoeringsstatus (duroxide schema) worden opgeslagen in normale tabellen en worden opgenomen in HorizonDB-back-ups. Met een herstel naar een bepaald tijdstip worden beide hersteld.
  • Leesreplica's. De achtergrondwerkrol wordt alleen uitgevoerd op de primaire. Leesreplica's kunnen query's uitvoeren op de df.* bewakingsweergaven, maar geen functies uitvoeren.
  • Failover. Na een failover gaat de worker op de nieuwe primaire verder waar de oude primaire is gebleven. Actieve instanties hervatten vanaf hun laatste controlepunt.

Vergeleken met externe orchestrators

Aspect Externe orchestrator pg_durable
Deployment Afzonderlijke service, afzonderlijke identiteit, afzonderlijke statusopslag Eén database
Bestendigheid van de toestand Opslaglaag van Orchestrator Dezelfde back-ups, HA en PITR als uw gegevens
Identity Werknemers worden uitgevoerd onder een service-id Functies worden uitgevoerd als de verzendende gebruiker
Faalmodi Netwerk tussen orchestrator en database Geen - hetzelfde proces
Ideaal voor Systeemoverschrijdende orkestratie die veel services omvat Workloads waar het meeste werk zich in of in de buurt van Postgres bevindt

pg_durable is niet bedoeld om externe orkestrators voor systeemoverstijgende pijplijnen te vervangen. Het is de juiste keuze wanneer het grootste deel van het werk databasewerk is: insluitingen, transformaties, AI-aanroepen, gepland onderhoud en het toevoegen van een andere service is duurder dan voordeel.

Beperkingen tijdens preview

  • df.http() opnieuw proberen bij 5xx- en netwerkfouten. 4xx-antwoorden worden teruggestuurd naar de workflow om daar te worden afgehandeld; ze worden niet automatisch opnieuw geprobeerd.
  • De achtergrondwerker bedient één database per instantie. Fan-out over meerdere databases wordt ondersteund via df.start(..., database => 'other_db') vanuit een functie die wordt uitgevoerd in de database van de worker.
  • Functiedefinities en uitvoeringsstatus zijn niet overdraagbaar in primaire versies van pg_durable tijdens de preview. Actieve exemplaren leegmaken of annuleren voordat u een upgrade uitvoert.