# Betrouwbare Apps Script-automatiseringen bouwen Een automatisering die af en toe faalt of per ongeluk dubbel werk doet, kost meer tijd dan ze bespaart. Met een paar vaste gewoonten maak je **Apps Script**-automatiseringen voorspelbaar en veilig. Dit artikel gaat over de techniek achter robuuste scripts; voor het instellen van triggers is er een apart artikel. ## Werk binnen de limieten Apps Script kent harde quota. De belangrijkste om rekening mee te houden: - **Looptijd per uitvoering:** een script mag maximaal zes minuten draaien. Daarna wordt de uitvoering afgebroken met de melding "Exceeded maximum execution time", ongeacht het accounttype. - **Totale triggertijd per dag:** voor consumentenaccounts is dit ongeveer 90 minuten per dag; voor Google Workspace-accounts is dit ruimer. - **Gelijktijdige uitvoeringen:** er draaien maximaal 30 uitvoeringen tegelijk per gebruiker. Daarnaast gelden er dagelijkse limieten voor onder meer verstuurde e-mails en URL Fetch-aanroepen, die afhangen van je accounttype en in de tijd kunnen wijzigen. Controleer de actuele waarden in de officiele quotapagina van Google voordat je op een specifiek getal bouwt. :::warn title="Pas op voor de zesminutenlimiet" Verwerk je veel rijen of veel mails, dan loop je tegen de zesminutenlimiet aan. Splits het werk dan op in batches: verwerk per run een vast aantal items, sla op waar je gebleven was, en laat een volgende triggeruitvoering verdergaan. ::: ## Maak je script idempotent Idempotent betekent dat een tweede uitvoering met dezelfde invoer niet voor extra effect zorgt. Dat is essentieel, want een trigger kan opnieuw draaien na een fout, en bij batchverwerking draait je functie meerdere keren. - Houd bij welke items al verwerkt zijn, bijvoorbeeld met een statuskolom in het Spreadsheet of een vlag in `PropertiesService`. - Sla verwerkte rijen over in plaats van blind alles opnieuw te doen. - Stuur geen mail of maak geen account aan zonder eerst te controleren of dat al gebeurd is. ```javascript function verwerkRijen() { const sheet = SpreadsheetApp.getActiveSheet(); const rijen = sheet.getDataRange().getValues(); for (let i = 1; i < rijen.length; i++) { if (rijen[i][3] === 'OK') continue; try { doeActie(rijen[i]); sheet.getRange(i + 1, 4).setValue('OK'); } catch (e) { sheet.getRange(i + 1, 4).setValue('FOUT: ' + e.message); console.error('Rij %s mislukt: %s', i + 1, e.message); } } } ``` ## Vang fouten op per item Een veelgemaakte fout is een grote `try` om de hele lus heen. Een kapotte rij stopt dan alles. Plaats de `try-catch` per item, zodat een enkele fout de rest niet blokkeert en je precies ziet welke regel misging. ## Log wat er gebeurt Een automatisering draait onzichtbaar. Zonder logging weet je niet waarom een run faalde. - Gebruik `console.log()`, `console.warn()` en `console.error()`. Deze schrijven naar de uitvoeringslogboeken (Cloud Logging), die je terugvindt bij **Uitvoeringen** in de editor. - Log het begin en einde van een run, en bij fouten de specifieke context, zoals een rijnummer of e-mailadres. - `Logger.log()` werkt ook, maar `console`-logs blijven langer bewaard en zijn beter doorzoekbaar. :::tip title="Stuur jezelf een samenvatting" Stuur jezelf een korte samenvattingsmail aan het einde van een dagelijkse run, bijvoorbeeld "42 verwerkt, 2 fouten". Zo merk je problemen zonder dat je actief de logs hoeft te openen. ::: ## Voorkom gelijktijdige botsingen Draait dezelfde functie soms tegelijk, bijvoorbeeld door een snelle trigger plus een handmatige start, dan kunnen twee runs dezelfde rij oppakken. `LockService` voorkomt dat: ```javascript function verwerkMetLock() { const lock = LockService.getScriptLock(); if (!lock.tryLock(10000)) return; try { verwerkRijen(); } finally { lock.releaseLock(); } } ``` ## Beveiliging - Zet geen wachtwoorden, API-sleutels of tokens hard in je code. Gebruik `PropertiesService` om gevoelige waarden buiten de broncode te houden. - Geef een script alleen de scopes die het echt nodig heeft; minder rechten betekent minder risico. - Deel een script alleen met mensen die het echt moeten beheren, want een installeerbare trigger draait onder het account van de maker. Met deze gewoonten, batchen binnen de limieten, idempotente verwerking, foutopvang per item, logging en een lock tegen botsingen, bouw je automatiseringen waar je daadwerkelijk op kunt vertrouwen. :::faq ### Wat gebeurt er als mijn script de zesminutenlimiet overschrijdt? De uitvoering wordt direct afgebroken met de melding "Exceeded maximum execution time". Werk dat al gedaan was blijft staan, maar de rest gebeurt niet. Daarom splits je groot werk op in batches en bewaar je per run waar je gebleven was. ### Hoe maak ik een script idempotent zonder een externe database? Houd de status bij in iets wat je toch al hebt: een statuskolom in het Spreadsheet, of een sleutel in `PropertiesService`. Controleer die status aan het begin van elk item en sla items over die al op OK staan. ### Waarom zou ik `console.log` gebruiken in plaats van `Logger.log`? Beide loggen, maar `console`-logs gaan naar Cloud Logging, blijven langer bewaard en zijn beter te doorzoeken en te filteren. `Logger.log` is vooral handig voor een snelle test in de editor. ### Wanneer heb ik `LockService` echt nodig? Zodra dezelfde functie tegelijk kan draaien, bijvoorbeeld een trigger plus een handmatige start, of meerdere triggers kort na elkaar. Zonder lock kunnen twee runs dezelfde rij oppakken en dubbel werk doen. ### Hoe weet ik of een dagelijkse run goed is gegaan zonder de logs te openen? Laat het script aan het einde een korte samenvattingsmail sturen met aantallen, bijvoorbeeld het aantal verwerkte items en het aantal fouten. Zo zie je in een oogopslag of er aandacht nodig is. :::