Blog ·
Een pauze die de bestelling openhield
Een wacht in een flow hield het bestelverzoek zijn hele duur lang open. De oplossing was een drempel en geen vinkje, en het getal is gemeten.
Door Provibr
Een flow kan een wacht bevatten. Je richt een machine in, je geeft de agent even de tijd, en dan stuur je het volgende commando. Tot deze week was die wacht een slaap binnen het verzoek dat de flow startte, wat betekende dat een klant die een bestelling plaatste de hele pauze lang naar een draaiend wieltje zat te kijken.
De oude bovengrens was vijf minuten. Iemand kon dus een volstrekt redelijk ogende flow bouwen waarvan het effect een bestelformulier van vijf minuten was.
Nu een run kan stoppen en door een worker voortgezet kan worden, hoeft de pauze niet meer binnen het verzoek te gebeuren. De bovengrens ging naar dertig dagen. De interessante vraag is echter niet het plafond. Het is waar de grens ligt tussen een pauze die het verzoek kan opvangen en een pauze die de run hoort op te schorten.
De drempel is gemeten, niet gekozen
Dertig seconden.
De vraag die we stelden was niet "hoe lang mag een pauze duren", waar geen antwoord op is, maar "hoeveel pauze verdraagt het verzoek waarin deze flow draait toch al", en daar is er wel een. Dat verzoek is de bestelling.
Gemeten tegen wat er al in gebeurt: een actieknoop wacht standaard zestig seconden op een commando en mag tot driehonderd ingesteld worden, en een melding met e-mail kost ongeveer een halve seconde per ontvanger. Een pauze die daar nog een halve minuut bovenop legt is verdedigbaar. Een pauze die er een hele minuut bovenop legt niet.
Hier zit een val in waar we bewust in gelopen zijn in plaats van omheen. De comfortabele keuze was geweest om de drempel op de oude bovengrens van driehonderd seconden te zetten, want dan gedraagt elke bestaande graaf zich precies als voorheen en is niemand verrast. Dat is ook fout: het houdt de hele klasse problemen in stand die aanleiding was voor de wijziging. Grafen met een pauze tussen eenendertig en driehonderd seconden gedragen zich nu wél anders. Hun bestelling is eerder klaar en de rest van de flow volgt later. Dat is de verbetering, niet de prijs ervan.
Het plafond van dertig dagen is een productregel en geen technische grens. De wachtmachinerie zou een run met alle plezier een jaar vasthouden. Wat geen jaar kan duren is een organisatie waarin niemand meer weet waarom een run openstaat.
Waarom het een drempel is en geen vinkje
Het voor de hand liggende alternatief is een schakelaar "duurzaam wachten" op de knoop. Die hebben we niet gebouwd, en de reden is een vraag die je niet kunt beantwoorden.
Als er een vinkje was, wanneer zou je het dan uit willen hebben? Het eerlijke antwoord is nooit. Duurzaam wachten is een implementatiedetail: wie een flow schrijft drukt uit "pauzeer hier zo lang" en heeft geen mening over de vraag of dat een databaserij kost. Een instelling waarvan de juiste waarde altijd dezelfde is, is geen instelling maar iets wat je vergeten bent te beslissen.
Dus typt de schrijver een aantal seconden en beslist de drempel. Onder de streep slaapt de wandeling gewoon, binnen het verzoek, zonder dat het iets kost. Erboven schrijft de run zijn voortzetting met een wektijd naar de wachtrij en keert de aanroeper meteen terug.
De stap die uiteindelijk in het runlogboek verschijnt draagt een duurzaamheidsvlag en de werkelijk gemeten verstreken tijd in plaats van de gevraagde, want dat zijn niet dezelfde getallen en het verschil is de enige manier om te zien dat de wachtrij achterloopt.
Flows die flows aanroepen, en twee grenzen die elk twee keer getoetst worden
De tweede helft van dit werk is een subflowknoop: een flow die een andere flow draait en daarop wacht.
Dat levert twee manieren op om iets te bouwen dat nooit eindigt, en ze lijken genoeg op elkaar om ze verleidelijk samen te toetsen. Ze zijn niet hetzelfde. Een cykel is oneindig. Een keten die te diep is, is eindig maar te lang. Beantwoord je allebei met één functie, dan wordt een cykel gemeld als "te diep", en gaat de schrijver een lange keten zoeken terwijl de zijne twee flows lang is.
Er zijn dus twee vragen, en elk wordt twee keer gesteld.
Ze worden één keer gesteld als een flow opgeslagen wordt, statisch, tegen de andere flows in de organisatie. Die controle moet er zijn omdat het de enige plek is waar een goede foutmelding mogelijk is: hij kan de flow noemen die de lus sluit.
Ze worden opnieuw gesteld tijdens de run. Die controle moet er zijn omdat flows onafhankelijk van elkaar bewerkt worden. Flow A wordt opgeslagen en is in orde. Daarna bewerkt iemand flow C, die nu terugwijst naar A. Niets hervalideerde A. De statische controle is een dienst aan de schrijver; de dynamische is de werkelijke garantie.
Twee implementatiedetails zijn het benoemen waard. De vraag "kan deze flow zichzelf in minstens één stap bereiken" beantwoordt het directe en het indirecte geval in één query, en die "minstens één" is de hele definitie: een pad van nul stappen zou elke flow zichzelf laten bereiken. En de dieptewandeling houdt zijn eigen pad bij en geeft oneindig terug zodra hij een flow tegenkomt die er al op staat, zodat hij niet blijft hangen op precies de invoer waarvoor de cykelcontrole bestaat. Dat is van belang omdat het betekent dat de twee controles in willekeurige volgorde gedraaid kunnen worden, en dus dat niemand een volgorderegel hoeft te onthouden.
Diepte staat als kolom op de kindrun, wat tegen onze gebruikelijke lijn ingaat dat een afleidbare waarde geen kolom is. De vreemde sleutel naar de ouder wordt op null gezet zodra de ouder verwijderd wordt, dus na een verwijdering kan de keten niet meer teruggelopen worden om hem opnieuw te berekenen. Een afgeleide waarde waarvan de bron kan verdwijnen is niet afleidbaar.
De terugvalklok is een dag en geen vijf minuten
Als een kindrun klaar is, zet hij de wektijd op de wachtregel van de ouder op nu, en wordt de ouder binnen tien seconden opgepakt. Dat is het mechanisme.
Er is ook een terugvalklok, voor het geval dat niet gebeurt: een container die halverwege het afronden van het kind omviel, een rij die met de hand is aangeraakt. Die staat op vierentwintig uur.
Vijf minuten zou de instinctieve keuze zijn en het is de verkeerde. Een kind dat op een goedkeuring wacht mag legitiem dertig dagen wachten. Met een korte klok zou de ouder in die periode duizenden keren wakker worden om vast te stellen dat er niets veranderd is, en elk van die keren is een HTTP-verzoek van de gateway naar de webcontainer. Een dag begrenst de schade van een gemist signaal tot een dag en kost hoogstens dertig zinloze wekkingen over de langste wacht die het systeem toestaat.
Een goedkeuring waar niemand van weet is een vastgelopen run
Een goedkeuringsverzoek kan nu een e-mail sturen, en de categorie waaronder hij verstuurd wordt is een eigen categorie en niet de algemene flowcategorie. Dat was een bewuste afwijking van het plan.
De algemene flowcategorie gaat naar iedereen die de automatiseringsmodule heeft. Een goedkeuringsverzoek hoort naar de mensen te gaan die er werkelijk over kunnen beslissen, en dat is een andere en kleinere groep. Er zit dus een tweede zeef op de categorie: de melding wordt alleen bezorgd bij leden die het beslissingsrecht hebben.
Gemeten op onze testorganisatie: de algemene flowcategorie kwam uit op drie ontvangers en de goedkeuringscategorie op twee. Twee getallen die verschillen zijn het hele bewijs dat de zeef iets doet.
Een klik die niets selecteerde
De meetles van deze ronde gaat over de browsertest en niet over het product.
Onze browserhulp heeft een klikmethode die de muisknop indrukt en weer loslaat. Op een gewone knop werkt dat. Op een knoop in het flowcanvas doet het helemaal niets: het eigenschappenpaneel bleef op de triggerknoop staan en de keuzelijst die we wilden wijzigen bestond niet, wat precies leest als een ontbrekende functie.
Het canvas begint bij een pointerdruk een sleep en roept setPointerCapture op de knoop aan. Zonder een voorafgaande muisbewegingsgebeurtenis, en zonder het veld buttons op de druk, produceert de browser geen klik die het capture-pad herkent. Die twee toevoegen maakt de selectie onmiddellijk.
Er zit nog een tweede detail in dezelfde hulp. Klik niet op het midden van een knoop. Het midden van een knoop met poorten ligt tussen de poortstippen, en die hebben hun eigen pointerafhandeling om er een draad uit te trekken. Klik in plaats daarvan linksboven op de kop.
Allebei zien ze eruit als productfouten als je ze tegenkomt, en dat is geen van beide. Dat is de algemene vorm van het probleem: een invoersimulatie die bijna klopt faalt op een manier die niet te onderscheiden is van een defect in precies het ding dat je probeerde te testen.
Wat we zouden opschrijven
- Een drempel wint van een vinkje zodra de juiste waarde van dat vinkje altijd dezelfde is. Vraag wanneer iemand hem uit zou zetten; is er geen antwoord, bouw de schakelaar dan niet.
- Meet de drempel tegen het budget waar hij in moet passen, niet tegen de functie die je begrenst.
- Zet de nieuwe drempel niet op de oude grens alleen omdat er dan niets verandert. Dat er niets verandert is het probleem dat je aan het oplossen was.
- Een cykel en een te lange keten zijn verschillende fouten. Eén melding voor allebei stuurt mensen naar de verkeerde plek.
- Valideer bij het opslaan voor de melding en tijdens de run voor de garantie. Naburige records veranderen zonder dat de jouwe opnieuw gevalideerd wordt.
- Een zoektocht die op zijn eigen pad stopt kan in willekeurige volgorde gedraaid worden ten opzichte van de controle die hij ondersteunt, en dat haalt een volgorderegel weg die niemand zou onthouden.
- Een afgeleide waarde waarvan de bron verwijderd kan worden is niet afgeleid. Sla hem op.
- Stem een terugvalklok af op de langste legitieme wacht, niet op hoe snel je het zou willen merken.
- Routeer een melding op wie erop kan handelen, niet op de module waar hij bij hoort.
- Een gesimuleerde invoer die bijna klopt faalt als een kapotte functie. Kijk hoe het component gebeurtenissen werkelijk ontvangt voordat je de uitslag gelooft.
Voor de duidelijkheid over wat dit is: de mergeverificatie draaide 16 van de 16 stappen zonder een faalregel, de websuite was 4583 groen, de package-, gateway- en toolssuites 7286 groen, de wandelingstests 75 groen, de subflowcontroles 13 groen, de end-to-end-run tegen de ontwikkeldatabase 58 groen, de ontvangersmeting 4 groen en de browsertest 31 groen met een echte gatewayworker, waarin een pauze van negentig seconden na vijfennegentig seconden hervatte, een ouderrun en een kindrun aan elkaar gekoppeld werden, precies één goedkeuringsmail verstuurd werd, en een keten van vier en een recursieve verwijzing allebei geweigerd werden met de veroorzakende keten bij naam in de melding. De editortest was 9 groen en de toegankelijkheidsveeg vond niets op zes pagina's. Onbewezen: de takken voor uitgeputte pogingen en verlopen claims, de terugvalklok van vierentwintig uur, een subflow binnen een lus, een verdwenen kindrun, de e-mail naar iemand die geen eigenaar is via een echte verzending, en helemaal niets tegen een echte hypervisor.
Uit het platformwerk aan Provibr. Hoe de wandeling om te beginnen leerde stoppen staat in elke zelfaanroep stond in staartpositie, en de vorm van de graaf zelf staat in een flow is een graaf, en die moet eindig zijn.