clickSomo

Funnels & triggers

Een funnel is een graaf. Een run is een rij. Een wachttijd is een tijd.

Dat is het hele model, en elke moeilijke eigenschap die dit product heeft komt uit die drie zinnen. Een live funnel bewerken is er veilig door. Een retry kan niet dubbel versturen erdoor. Iemand die op dinsdag uitschrijft, hoort op donderdag niets meer erdoor.

Wat er echt gebeurt als het draait

Het publiceren van een funnel schrijft een onveranderlijke versie. Iemand komt binnen, en er verschijnt een rij: één run, voor dit contact, gekoppeld aan die versie, met de huidige node, een wektijd en een eigen context.

Een worker least de runs waarvan de wektijd verstreken is en claimt ze met SKIP LOCKED, zodat twee workers niet dezelfde kunnen pakken. Het voert nodes uit tot het een wachttijd of een terminal bereikt, schrijft dan de volgende wektijd en laat los.

Een node is een pure functie van de run, het contact en de node — en de effecten ervan worden in dezelfde transactie gecommit als de voortgang van de run zelf. Die ene eigenschap maakt een retry veilig. Een worker die in het halve seconde tussen "versturen" en "voortzetten" wordt gedood, laat of beide of geen van beide achter, nooit één.

En omdat de app de tijd levert in plaats van de database, is een rij die nu wordt geschreven nu aan de beurt. Een planningskolom die standaard de klok van de database gebruikt is op het moment van schrijven nog niet aan de beurt, en mist precies de tick die hem creëerde — een bug die eruitziet als niets totdat een bericht een uur te laat is.

Eén tick van de workerUitvoering
  • 1Leasenwake_at <= now(), FOR UPDATE SKIP LOCKED. Een wachtrij zonder leases verstuurt standaard dubbel.
  • 2UitvoerenNodes op volgorde tot een wachttijd of een terminal. Elk schrijft een stap: wat het besloot, wat het uitstuurde.
  • 3CommitEffecten en voortgang, één transactie. Dit is de hele truc.
  • 4SlaapVolgende wake_at geschreven. Er bestaan nog geen downstream-rijen, en die hoeven ook niet.

Eén run per contact per versie

Veertien triggers

Wat een run kan starten

Sommige hiervan zijn dingen die jij doet. De meeste zijn dingen die je klant doet, of niet doet — en het uitblijven van een actie is net zo goede een trigger als de actie zelf.

Ze komen binnen

form_submit, list_join, contact_created, tag_added en segment_enter. Een segment is een live predicaat, dus "komt in het segment" dekt elke "is geworden" die je kunt uitdrukken — drie bestellingen, negentig dagen stil, geeft meer uit dan een drempel.

Ze doen iets

page_visit vanaf de site-snippet, message_opened, link_clicked, booking_made en payment_made. Dat een bericht wordt geopend is zelf al een event op het contact, dus één funnel kan wachten op een reactie op het laatste wat hij verstuurde.

Tijd, of jij

date_field met een offset — een verjaardag, een verlenging, "een jaar geleden", zeven dagen ervoor of drie dagen erna. schedule voor de terugkerende. manual voor de aankondiging die je verstuurt omdat jij dat besloot.

Je eigen applicatie

api_event is een custom event dat je vanuit je eigen code post met je eigen token. Alles wat je product weet wordt een trigger: geactiveerd, een collega uitgenodigd, de limiet bereikt, geannuleerd, geëxporteerd. Dit is degene die een mailingtool onderdeel maakt van je product.

Herhaling, eenmalig besloten

Een funnel is herintreedbaar of niet, en de database dwingt dat af: één run per contact per funnel, tenzij je anders zegt. Dezelfde trigger die twee keer in dezelfde seconde afgaat, kan niet per ongeluk twee runs opleveren.

Instapvoorwaarden

Een trigger gaat af en de instapspecificatie bepaalt of dit specifieke contact in aanmerking komt — een segmentpredicaat voor de deur. Goedkoper dan een conditieknooppunt op de eerste stap, en het houdt de grafiek over wat er gebeurt in plaats van over wie erin mag.

Vier dingen kunnen het starten. Zestien dingen kunnen er daarna gebeuren.

Zestien acties en zeven flowknooppunten

Wat een funnel kan doen, en hoe hij beslist

Iets versturen

send_email, send_sms, send_push, send_letter — vier kanalen, één grafiek — plus notify_team voor als degene die het moet weten voor je werkt.

Het contact wijzigen

add_tag, remove_tag, add_to_list, remove_from_list, set_field. Onderweg iemand markeren is wat het segment van de volgende funnel eenvoudig maakt.

Buiten bereik

http_request naar alles wat je wilt, create_payment op je eigen gekoppelde account, en book_slot op een boekingsresource. De betaler blijft van jou; niemand wordt onze klant.

Tussen funnels bewegen

enter_funnel en exit_funnel. Bouw één welkomstreeks en roep die vanaf vier plekken aan, in plaats van vier kopieën te onderhouden die in maart uit elkaar zijn gedreven.

Genereren op verzendmoment

ai_generate vult merge-variabelen per contact in, gemeten tegen je quota en gecachet op hash van creatief en contactattribuut — anders betaal je per ontvanger bij elke enkele verzending.

Wachten, vertakken, splitsen, samenvoegen

wait accepteert een duur, een datumtijd, een weekdag en tijdstip, of een datumveld met offset. condition is een segmentpredicaat met een ja en een nee. split is A/B/n met gewichten. join brengt takken weer samen.

goal — degene die er toe doet

Een doel beëindigt de run voor iedereen die het bereikt. Ze hebben geboekt, gekocht, geantwoord: de rest van de reeks wordt specifiek voor hen geannuleerd. Niemand krijgt "we missen je" de dag nadat hij terug is gekomen, en dit is het knooppunt dat dat voorkomt.

throttle en quiet_hours

Throttle tempert een uitbarsting zodat een mailbox met een lage ratelimiet niet in de schorsing wordt gedrukt. Quiet hours houden een bericht vast tot een fatsoenlijk tijdstip — toegepast op de berichtlaag, niet gekopieerd naar elke tak van de grafiek.

Gecontroleerd voordat het kan draaien

De validator weigert dezelfde dingen voor jou als voor de AI

Een grafiek wordt gecontroleerd voordat hij gepubliceerd kan worden, en de controle is niet adviserend. Het is hetzelfde codepad of een persoon de funnel tekende of een model hem genereerde, en dat is de enige reden dat gegenereerde funnels überhaupt te vertrouwen zijn.

Precies één instap

Twee instapknooppunten is een ambiguïiteit die niemand opmerkt totdat de verkeerde helft van een lijst de verkeerde reeks krijgt.

Elk knooppunt bereikbaar

Een verweesde tak is óf een fout óf een bericht waarvan jij denkt dat het eruit gaat en dat niet gaat. Beide zijn het melden waard.

Elke cyclus moet een wait bevatten

Een lus zonder wait is een oneindige lus met een verzending in het midden. Deze regel is het verschil tussen een funnel en een incident.

Elke verzending heeft zijn creatief

Een send_email-knooppunt zonder creatief en onderwerp kan niet gepubliceerd worden. Het bericht met het juiste onderwerp en een lege body is een echte faalwijze; hier wordt die geweigerd.

Elke variabele is bekend

Merge-variabelen worden gevalideerd bij publicatie. {{frist_name}} is een typefout die je ziet tijdens het bewerken, niet "Hallo ," dat in veertigduizend inboxen aankomt.

Simuleer het dan

Draai een echt contact als proefrun door de hele grafiek en lees het gevolgde pad terug plus elk bericht dat verstuurd zou worden, met zijn dag. Er verlaat niets het gebouw.

De lastige gevallen

Zeven dingen die een naïeve engine breken

Elk van deze is een test met een deterministische klok erachter, omdat elk daarvan een implementatie breekt die er perfect correct uitziet totdat hij de werkelijkheid ontmoet.

Waar de engine tegen getest wordtFalsificatie
  • 1Een trechter die in zichzelf looptLegitiem, gebruikelijk en prima — mits de cyclus een wachttijd bevat, waarop de validator aandringt.
  • 2Iemand meldt zich onderweg afUitsluiting wordt gecontroleerd bij verzending, niet bij het in de wachtrij zetten. Controle bij het in de wachtrij zetten mailt de mensen die zich tijdens de wachttijd hebben afgemeld.
  • 3De trechter wordt bewerkt terwijl er tienduizend mensen in zittenZij lopen de versie waarmee ze binnenkwamen, tot het einde. Nieuwe deelnemers lopen de nieuwe.
  • 4Dezelfde trigger vuurt twee keer binnen één secondeEén run, want uniciteit is een index en geen controle gevolgd door een insert.
  • 5Een contactpersoon wordt midden in een run verwijderdDe run eindigt. Een verwijdering die een reeks achterlaat die nog steeds aan iemand geadresseerd is, is geen verwijdering.
  • 6Een wachttijd overlapt een zomertijdovergang"Drie dagen om negen uur 's ochtends" betekent negen uur 's ochtends aan beide kanten van de klokverandering.
  • 7Een worker wordt gedood tussen verzenden en vooruitschuivenEffecten en vooruitschuiven zijn één transactie. Of beide zijn gebeurd, of geen van beide.

Deterministische klokElke test breekt een plausibele implementatie

Campagnes zijn de andere helft

Een trechter reageert. Een campagne is de eenmalige uitzending: een publiek, een planning, een throttle en een verzending. Het is een ander soort ding en wordt bewust apart gehouden in plaats van zich voor te doen als een trechter met één knooppunt.

Twee regels maken het veilig. Een publiek wordt één keer gematerialiseerd en weigert twee keer te draaien — opnieuw resolven zou stilletjes iedereen toevoegen die zich sinds de start van de verzending heeft aangemeld, en de deduplicatie-index zou dat verbergen door de duplicaten te voorkomen die het zelf creëerde. En tellers worden herberekend uit aflevergebeurtenissen, nooit ter plekke opgehoogd, zodat een opnieuw geprobeerde webhook geen rapport kan opblazen.

Welke je gebruikt: als het gebeurt door iets dat de persoon deed, is het een trechter. Als het gebeurt door iets dat je op een dinsdag besloot, is het een campagne. Verrassend veel marketingautomatisering gaat mis door het tweede in de vorm van het eerste te dwingen.