clickSomo

Tragter & udløsere

En tragt er en graf. Et forløb er en række. En ventetid er et tidspunkt.

Det er hele modellen, og alle de svære egenskaber, dette produkt har, udspringer af de tre sætninger. Det er derfor, det er sikkert at redigere en live tragt. Det er derfor, et retry ikke kan sende dobbelt. Det er derfor, en person, der melder sig af på tirsdag, ikke hører noget på torsdag.

Hvad der faktisk sker, når den kører

Når man udgiver en tragt, skrives der en uforanderlig version. Nogen træder ind, og en række dukker op: ét forløb, for denne kontakt, fastgjort til den version, med den aktuelle node, et opvågningstidspunkt og sin egen kontekst.

En worker leaser de forløb, hvis opvågningstidspunkt er passeret, og gør krav på dem med SKIP LOCKED, så to workers ikke kan tage det samme. Den udfører noder, indtil den når en ventetid eller en terminal, skriver derefter det næste opvågningstidspunkt og slipper taget.

En node er en ren funktion af forløbet, kontakten og noden — og dens effekter committes i samme transaktion som forløbets eget fremryk. Den enkelte egenskab er det, der gør et retry sikkert. En worker, der dræbes i det halve sekund mellem "send" og "fremryk", efterlader enten begge eller ingen, aldrig kun én.

Og fordi appen leverer tidspunktet i stedet for databasen, er en række, der skrives nu, forfalden nu. En planlægningskolonne, der som standard bruger databasens ur, er ikke forfalden i det øjeblik, den skrives, og går glip af netop det tick, der skabte den — en fejl, der slet ikke ligner noget, før en besked er en time forsinket.

Ét tick af workerenEksekvering
  • 1Leasewake_at <= now(), FOR UPDATE SKIP LOCKED. En kø uden leases sender dobbelt som standard.
  • 2UdførNoder i rækkefølge, indtil en ventetid eller en terminal. Hver skriver et trin: hvad den besluttede, hvad den udsendte.
  • 3CommitEffekter og fremryk i én transaktion. Det er hele tricket.
  • 4SøvnNæste wake_at skrevet. Der findes endnu ingen downstream-rækker, og ingen behøver at gøre det.

Ét forløb pr. kontakt pr. version

Fjorten udløsere

Hvad kan starte et forløb

Nogle af disse er ting, du gør. De fleste er ting, din kunde gør, eller ikke gør — og fraværet af en handling er lige så god en udløser som selve handlingen.

De ankommer

form_submit, list_join, contact_created, tag_added og segment_enter. Et segment er et levende prædikat, så "træder ind i segmentet" dækker alt, hvad du kan udtrykke som "er blevet" — tre ordrer, halvfems dages stilhed, forbrug over en grænse.

De gør noget

page_visit fra site-snippetten, message_opened, link_clicked, booking_made og payment_made. At en besked åbnes er i sig selv en hændelse på kontakten, så én tragt kan vente på en reaktion på det sidste, den sendte.

Tiden, eller dig

date_field med en forskydning — en fødselsdag, en fornyelse, "et år siden", syv dage før eller tre dage efter. schedule til den tilbagevendende. manual til den udmelding, du sender, fordi du besluttede det.

Din egen applikation

api_event er en brugerdefineret hændelse, du poster fra din egen kode med din egen token. Alt, hvad dit produkt ved, bliver en udløser: aktiveret, inviterede en kollega, ramte grænsen, annulerede, eksporterede. Det er den, der forvandler et mailingværktøj til en del af dit produkt.

Genindtræden, besluttet én gang

En tragt er enten genindtrædende eller ikke, og databasen håndhæver det: ét forløb pr. kontakt pr. tragt, medmindre du har sagt andet. Den samme udløser, der udløses to gange i samme sekund, kan ikke ved et uheld give to forløb.

Indgangsbetingelser

En udløser udløses, og indgangsspecifikationen afgør, om netop denne kontakt er berettiget — et segmentprædikat foran døren. Billigere end en betingelsesnode på det første trin, og det holder grafen om, hvad der sker, snarere end om, hvem der har lov at komme ind.

Fjorten ting kan starte den. Seksten ting kan ske bagefter.

Seksten handlinger og syv flownoder

Hvad en tragt kan gøre, og hvordan den beslutter

Send noget

send_email, send_sms, send_push, send_letter — fire kanaler, én graf — plus notify_team, når den person, der skal have det at vide, arbejder for dig.

Ændr kontakten

add_tag, remove_tag, add_to_list, remove_from_list, set_field. At markere nogen undervejs er det, der gør næste tragts segment enkelt.

Ræk udadtil

http_request til hvad du vil, create_payment mod din egen tilknyttede konto, og book_slot mod en bookingressource. Betaleren forbliver din; ingen bliver vores kunde.

Bevæg dig mellem tragter

enter_funnel og exit_funnel. Byg én velkomstsekvens og kald den fra fire steder, i stedet for at vedligeholde fire kopier, der driver fra hinanden inden marts.

Generér ved afsendelsestidspunktet

ai_generate udfylder merge-variabler pr. kontakt, målt mod din kvote og cachet efter hash af kreativ og kontaktattribut — ellers ville du betale pr. modtager ved hver eneste afsendelse.

Vent, forgren, split, forbind

wait tager en varighed, et datotidspunkt, en ugedag og et klokkeslæt, eller et datofelt med et offset. condition er et segmentprædikat med et ja og et nej. split er A/B/n med vægte. join samler forgreningerne igen.

goal — den, der tæller

Et mål afslutter kørslen for alle, der når det. De har booket, de har købt, de har svaret: resten af sekvensen annulleres specifikt for dem. Ingen får "vi savner dig" dagen efter, de er kommet tilbage, og det er denne node, der forhindrer det.

throttle og quiet_hours

Throttle dæmper en burst, så en postkasse med lav hastighedsgrænse ikke hamres i suspension. Quiet hours holder en besked tilbage til et civiliseret tidspunkt — anvendt på beskedniveau, ikke kopieret ind i hver gren af grafen.

Tjekket, før det kan køre

Validatoren nægter de samme ting for dig og for AI'en

En graf tjekkes, før den kan publiceres, og tjekket er ikke vejledende. Det er samme kodevej, uanset om en person har tegnet tragtén, eller en model har genereret den, og det er den eneste grund til, at genererede tragter overhovedet kan stole på.

Præcis ét indgangspunkt

To indgangsnoder er en flertydighed, ingen lægger mærke til, før den forkerte halvdel af en liste får den forkerte sekvens.

Hver node er nåelig

En forældreløs gren er enten en fejl eller en besked, du tror går ud, men som ikke gør. Begge dele er værd at få at vide.

En cyklus skal indeholde en wait

En løkke uden en wait i er en uendelig løkke med en afsendelse i midten. Denne regel er forskellen på en tragt og en hændelse.

Hver afsendelse har sin kreative

En send_email-node uden en kreativ og et emne kan ikke publiceres. Beskeden med det rigtige emne og en tom brødtekst er en reel fejltilstand; den afvises her.

Hver variabel er kendt

Merge-variabler valideres ved publicering. {{frist_name}} er en tastefejl, du ser, mens du redigerer — ikke "Hej ," der ankommer i fyrre tusind indbakker.

Simulér den derefter

Kør en tørkørsel med en rigtig kontakt gennem hele grafen og læs den tilbagelagte vej og hver besked, der ville blive sendt, med dens dag. Intet forlader bygningen.

De besværlige tilfælde

Syv ting, der bryder en naiv motor

Hver af dem er en test med et deterministisk ur bag, fordi hver enkelt bryder en implementering, der ser perfekt korrekt ud, indtil den møder virkeligheden.

Hvad motoren testes imodFalsifikation
  • 1En tragt, der looper ind i sig selvLegitimt, almindeligt og fint — forudsat at cyklussen indeholder en wait, hvilket validatoren insisterer på.
  • 2Nogen afmelder sig midt i forløbetUndertrykkelse tjekkes ved afsendelse, ikke ved kø. Tjek ved kø sender post til de folk, der forlod ventelisten under ventetiden.
  • 3Tragtén redigeres, mens ti tusind mennesker er inde i denDe fortsætter på den version, de kom ind på, til slutningen. Nye tilkomne går på den nye.
  • 4Samme trigger udløses to gange på ét sekundÉn kørsel, fordi unikhed er et indeks frem for et tjek efterfulgt af en insert.
  • 5En kontakt slettes midt i en kørselKørslen afsluttes. En sletning, der efterlader en sekvens, som stadig er adresseret til nogen, er ikke en sletning.
  • 6En ventetid strækker sig over en skift til/fra sommertid"Tre dage klokken ni om morgenen" betyder ni om morgenen på begge sider af ur-skiftet.
  • 7En worker dræbes mellem afsendelse og fremrykningEffekter og fremrykning er én transaktion. Enten er begge sket, eller ingen af dem.

Deterministisk urHver test knækker en plausibel implementering

Kampagner er den anden halvdel

En tragt reagerer. En kampagne er engangs-udsendelsen: et publikum, en tidsplan, en begrænsning og en afsendelse. Det er en anden slags ting, og den holdes bevidst adskilt i stedet for at udgive sig for at være en tragt med én knude.

To regler gør det sikkert. Et publikum materialiseres én gang og nægter at køre to gange — en ny opløsning ville i stilhed tilføje alle, der er kommet til, siden afsendelsen startede, og deduplikeringsindekset ville skjule det ved at forhindre de dubletter, det selv skabte. Og tællere genberegnes fra leveringshændelser og tælles aldrig op på stedet, så en webhook, der prøves igen, ikke kan puste en rapport op.

Hvad skal du bruge: sker det på grund af noget, personen gjorde, er det en tragt. Sker det på grund af noget, du besluttede en tirsdag, er det en kampagne. Forbløffende meget marketingautomatisering går galt ved at tvinge det sidste ind i den førstes form.