Hoe beperk ik het aantal API-calls / bijgewerkte rijen in een UPDATE statement?

Invantive SQL maakt het massaal bijwerken en synchroniseren van data eenvoudig doordat de techniek onder de motorkap blijft. Met het update-statement en/of synchronize-statement kunt u eenvoudig massaal gegevens in cloudapplicaties bijwerken zodat al uw bedrijfsprocessen dezelfde gegevens gebruiken.

Sommige cloudapplicaties beperken uit technische, fair use en/of commerciële redenen het aantal API-calls. Vaak wordt bij overschrijding een foutmelding gegeven zoals “Too many requests” of een HTTP 429-statuscode.

De gangbare term voor een dergelijke beperking van API-calls is een “rate limit”. Soms zijn meerdere rate limits van toepassing, bijvoorbeeld per dag, per maand, per minuut, per API, per API-operatie (lezen/schrijven) of per API-resultaat: met of zonder foutmelding.

Vaak kunnen dan extra API-calls bijgekocht worden zodat de rate limit hoger komt te liggen, hetzij met betaling vooraf, hetzij met afrekening achteraf. Op sommige platformen is verruiming van de API-call rate limit tot hogere/extra limieten relatief duur met uitschieters tot enkele tientallen Euro’s per stuk voor complexe calls, op andere extreem spotgoedkoop.

Het is verstandig om de beschikbare ruimte in rate limits qua API-calls op de juiste momenten in te zetten als de aantallen gelimiteerd zijn per tijdseenheid zoals maand of dag. Aanpassingen met lage prioriteit voert u door aan het einde van de periode om maximaal rendement te halen uit uw investering in het cloudplatform.

Varieer het aantal API-calls in de tijd alleen nadat u eerst het aantal API-calls beperkt heeft; functionele tips hiervoor leest u in Hoe plan ik mijn Exact Online-omgeving op het beschikbare aantal API-calls? en technische tips in bijvoorbeeld Snel en met minder API-calls Exact Online uitlezen met de incrementele "sync API"-tabellen.

Invantive SQL biedt faciliteiten om de beschikbare rate limits ruimte qua API-calls zo effectief mogelijk te gebruiken. De beschikbare ruimte is bij de meeste platformen zichtbaar in kolommen van de datadictionary-view SystemPartitions@DataDictionary. Hierin zijn kolommen voor de rate limits per dag, uur en minuut, en het aantal verzoeken in het huidige dag, uur en minuut.

Voor het synchronize-statement kunt u opgeven hoeveel mutaties maximaal plaatsvinden. Dit is echter ook mogelijk met de traditionele update, delete en insert SQL-statements.

Het maximum aantal mutaties voor update, delete, insert kunt u instellen via limit GETAL, net zoals limit het aantal rijen uit een selectie via select beperkt.

Aan de hand van een praktijkcasus met de Exact Online API wordt dit geïllustreerd.

Casus: Aanpassen Factuurbijlages

In het Exact Online boekhoudsysteem kunt u per relatie in een administratie vastleggen in welke formaten de facturen verzonden worden. Dit kan een combinatie van formaten zijn, die gecombineerd worden tot een getal via de zogenaamde “bitwise AND”. De waarde “1” betekent bijvoorbeeld alleen verkoopfacturen in PDF-formaat, de waarde “2” betekent UBL-formaat en de waarde “3” betekent zowel PDF- als UBL-formaat.

In een Exact Online database met administraties met elk 50.000 relaties dient bij alle administraties het formaat van de factuurbijlages omgezet te worden van PDF plus UBL naar alleen PDF. Echter, het aantal API-calls per dag is op Exact Online maar een fractie van de 50.000 benodigde API-calls en de omzetting heeft een lagere prioriteit dan de dagelijkse verwerkingen.

Daarom worden aan het einde van de dag de mutaties doorgevoerd in Exact Online om eventueel resterend API-call budget te consumeren met deze extra verzoeken.

De hoogste prioriteit heeft deze mutatie op verkoopklanten; de overige relaties hebben nog geen klantstatus.

In de job kan het aantal mutaties op Exact Online beperkt worden tot 10 via de volgende update:

use SELECTIE_ADMINISTRATIES@eol

update exactonlinerest..accounts@eol
set    InvoiceAttachmentType = 1
where  InvoiceAttachmentType = 3
and    status = 'C'
limit  100

Merk op dat hierbij geen gebruik gemaakt worden van de Exact Online-tabel AccountsIncremental; deze is alleen-lezen en zou een complexer synchronize-statement vereisen, terwijl de where-clause dankzij Invantive’s server-side filtering en Exact Online’s filter rechtstreeks aan de Exact Online doorgegeven kan worden waardoor maar 1 Exact Online API-call nodig is om de bij te werken rijen op te vragen.

Dit statement zal - indien er nog klanten zijn waarvoor een aanpassing nodig is - na pakweg 3 seconden klaar zijn.

Een eventueel restant API-callbudget kan gebruikt worden om ook voor de niet-klanten de soort factuurbijlages in te stellen:

use SELECTIE_ADMINISTRATIES@eol

update exactonlinerest..accounts@eol
set    InvoiceAttachmentType = 1
where  InvoiceAttachmentType = 3
limit  100

Verfijning: meer administraties

Het massaal aanpassen kan eenvoudig uitgebreid worden naar meerdere administraties. Geef hiervoor eerst de administratieselectie op, bijvoorbeeld voor alle Exact Online administraties:

use all@eol

update exactonlinerest..accounts@eol
set    InvoiceAttachmentType = 1
where  InvoiceAttachmentType = 3
and    status = 'C'
limit  1000

update exactonlinerest..accounts@eol
set    InvoiceAttachmentType = 1
where  InvoiceAttachmentType = 3
limit  1000

Aangezien op Exact Online momenteel de API-limieten per administratie gelden, is het mogelijk om de limiet hoger in te stellen. In dit voorbeeld is uitgegaan van 10 administraties, waarbij de 1000 updates door de parallelle verwerking grofweg uitgesmeerd zullen worden over alle 10, tenzij de hoeveelheid benodigde API-updates per administratie significant varieert.

Verfijning: alleen vrije API-call ruimte in zo kort mogelijke tijd

Een meer geavanceerde verfijning is het beperken van het aantal API-calls tot het beschikbare aantal voor een administratie, plus het minimaliseren van de doorlooptijd (zonder parallellisatie).

Het volgende blok Invantive PSQL vuurt telkens korte reeksen van updates af, waarbij de lengte zo gekozen is dat de Exact Online-minuutlimiet van 60 API calls per minuut zo snel mogelijk wordt volgemaakt:

declare
  l_did_work  boolean;
  l_dummy_cnt number;
  g_max_call_per_minute pls_integer := 50 /* Iets lager dan 60 om vaker te kunnen wisselen. */;
begin
  use all@eol;
  --
  -- Zorg dat de cijfers qua resterende API-calls actueel zijn
  -- door alle administraties even te raken.
  --
  select /*+ http_disk_cache(false) http_memory_cache(false) */ count(*)
  into   l_dummy_cnt
  from   exactonlinerest..journals@eol
  ;
  l_did_work := true;
  while l_did_work
  loop
    dbms_output.put_line('Gedurende een minuut de API-call minuutlimieten proberen te halen per administratie.');
    l_did_work := false;
    for r
    in 
    ( select 'update exactonlinerest..accounts@eol'
              || ' set InvoiceAttachmentType = 1'
              || ' where  InvoiceAttachmentType = 3'
              || ' limit  ' 
              || to_char
                 ( case
                   when DAILY_REMAINING > g_max_call_per_minute
                   then g_max_call_per_minute
                   else DAILY_REMAINING
                        --
                        -- Laat 500 Exact Online API-calls over voor onverwachte 
                        -- prioriteiten later vandaag.
                        --
                        - 500
                   end
                 )
              stmt
       ,      'Werk maximaal ' 
              || g_max_call_per_minute 
              || ' rijen bij in administratie ' 
              || code
              || ' - ' 
              || name 
              txt
       from   SYSTEMPARTITIONS@DataDictionary
       where  IS_SELECTED = true
       and    PROVIDER_NAME = 'ExactOnlineAll'
       and    PROVIDER_DATA_CONTAINER_ALIAS = 'eol'
       --
       -- Er moeten nog tenminste 500 API-calls over zijn
       -- vandaag voor deze administratie.
       --
       and    DAILY_REMAINING > 500
    )
    loop
      dbms_output.put_line(r.txt);
      execute immediate r.stmt;
      l_did_work := true;
    end loop;
  end loop;
end;