Dette kapitel beskriver, hvordan hændelser fungerer på Datafordeleren som et værktøj til at holde registerdata synkroniseret. Hændelser giver anvendere mulighed for at modtage automatiske notifikationer, når data ændres, så de kan holde egne løsninger opdaterede uden at skulle forespørge unødigt efter data.
For et register er en hændelse en ændring af data. En hændelse kan således være resultatet af et trin i en forvaltningsproces (også omtalt som en forretningsproces), som opdaterer data i et register.
Hændelser oprettes automatisk som strukturerede notifikationer, når ændringerne i registerdata indlæses på Datafordeleren. Det fungerer som et system, der kommunikerer dataændringer, når anvendere opretter en forbindelse ved at abonnere på hændelser eller henter hændelser via queries.
Ved at bruge hændelser, kan anvendere hente opdateringer, og holde deres egne data synkroniseret med de nyeste ændringer. For eksempel hvis en virksomhed skifter navn, vil anvendere få en hændelsesbesked, hvorefter de kan opdatere deres kopiregister.
Hændelser er opdelt per register, så anvendere kan vælge kun at modtage hændelser for de enkelte registre, de har behov for. Hændelser per register er implementeret som en entitet, der fungerer på samme måde som andre entiteter, som kan hentes gennem Datafordelerens GraphQL-tjenester. F.eks. har BBR en entitet, der hedder BBR_Events, gennem hvilken alle hændelser for BBR kan hentes.
Hændelser indeholder metadata om ændringerne i registerdata, herunder:
Hændelser er gjort tilgængelige for anvendere med to forskellige metoder:
Typisk vil hændelser blive brugt i en totrinsproces:
Hændelser der modtages via GraphQL kan indeholde felterne som vises i Tabel 2, hvis anvender inkluderer dem i sin query.
Feltnavn |
Betydning |
|---|---|
eventid |
Identifikator for den specifikke hændelse. |
entityname |
Navnet på entiteten som hændelsen omhandler. |
eventaction |
Handlingen som er foretaget for at ændre registerdataene. Kan enten være "i" for insert, "u" for update, eller "d" for delete. |
datafordelerRegisterImportSequenceNumber |
Registeret dataindlæsningspakke-sekvensnummer, der indeholder ændringen. |
datafordelerOpdateringstid |
Tidspunktet hvor dataene (hændelsen) er blevet indsat i databasen hos Datafordeleren. |
fromfailedimport |
Indikator for om hændelsen er fra en fejlet import, og derfor vil være en duplikat, for at anvendere kan håndtere det i deres løsninger. |
object_id |
ID på registerdata-objektet som er opdateret. Genereret af registeret, hvis det findes for den specifikke entitet. |
object_datafordelerRowId |
Identifikator for registerdata-objektet som hændelsen omhandler. Genereret af Datafordeleren. |
object_datafordelerRowVersion |
Versionen for registerdata-objektet. Feltet starter med værdien 1 og stiger med 1 hver gang registeret opdaterer rækken. |
object_registreringfra |
Den nye værdi af "registrering fra", fra hændelsens registerdata-objekt, der er blevet opdateret – forudsat at et sådant felt findes. |
object_registreringtil |
Den nye værdi af "registrering til", fra hændelsens registerdata-objekt, der er blevet opdateret – forudsat at et sådant felt findes. |
object_status |
Den nye værdi af status, fra hændelsens registerdata-objekt, der er blevet opdateret – forudsat at et sådant felt findes. |
object_virkningfra |
Den nye værdi af "virkning fra", fra hændelsens registerdata-objekt, der er blevet opdateret – forudsat at et sådant felt findes. |
object_virkningtil |
Den nye værdi af "virkning til", fra hændelsens registerdata-objekt, der er blevet opdateret – forudsat at et sådant felt findes. |
Tabel 2: Datafelter i hændelser
Data i en hændelse er i høj grad baseret på det underliggende dataobjekt, som hændelsen refererer til. En dybere forståelse af felterne kræver derfor kendskab til de specifikke entiteter, som hændelserne er baseret på, og deres struktur.
Anvendere kan filtrere entiteter baseret på bitemporale data ved hjælp af inputvariablerne object_registreringfra, object_registreringtil, object_virkningfra og object_virkningtil, hvilket muliggør mere præcis og kontekstspecifik datahentning. Nogle entiteter understøtter forespørgsler på begge dimensioner, mens andre kun understøtter én af værdierne - hvilke bitemporale dimensioner, der understøttes for en given entitet, kan ses i tjenestens GraphQL-skema. Læs mere om filtrering og tilladte operatorer i afsnit 4.2 (Mulige filtreringer).
CPR-registeret har specielle filtreringsmuligheder, der ikke findes i andre registre. Dette skyldes CPR's unikke behov for at kunne spore borgeres tilknytning til kommuner over tid, hvilket er relevant for mange offentlige myndigheder og private virksomheder, der arbejder med persondata. Disse vises i Tabel 3.
De to yderligere felter giver mulighed for at filtrere hændelser baseret på borgeres kommunetilhørsforhold, både nuværende og historisk. Dette er særligt nyttigt når anvendere kun har behov for at modtage hændelser om borgere i specifikke kommuner, eller når de f.eks. skal håndtere kommuneskift.
Læs mere om filtrering af hændelser baseret på kommunekoder i afsnit 4.2.1.2 (CPR-felter).
Feltnavn |
Betydning |
object_kommunekodenuvaerende |
Den nuværende kommunekode for et dataobjekt som har ændret sig i CPR. |
object_kommunekodetidligere |
Den tidligere kommunekode for et dataobjekt som har ændret sig i CPR. |
Tabel 3: CPR-felter
Figur 1 illustrerer den overordnede arkitektur for distribution af hændelser via Datafordeleren. Data oprettes og vedligeholdes i registre og kopieres løbende til Datafordeleren gennem replikeringskanaler. Herefter indlæses data i Datafordelerens databaser, hvor der genereres hændelser baseret på den indlæste data. Datafordeleren distribuerer både registerdata og hændelser til anvendere, som kan tilgå data gennem forskellige tjenester, eksempelvis de entitetsbaserede GraphQL-tjenester.

Figur 1: Overordnet arkitektur for hændelser
Hændelser udstilles via GraphQL-tjenester, som følger de samme principper som der er beskrevet i *\[C0200-REST-GRAPHQL\]* og *\[C0200-ENTITETSBASEREDE-GRAPHQL\]{*}. De vigtige koncepter for moderniserede hændelser er: |
*Filtrering -* Anvender samme filtreringsoperatorer (eq, gt, in, osv.) som beskrevet i *\[C0200-REST-GRAPHQL\]{*}. |
Der kan være forskellige scenarier for, hvordan en anvender ønsker at modtage hændelser. Har man ikke behov for at modtage opdateringer med det samme, kan man hente hændelser med queries mod GraphQL-tjenesterne, beskrevet i afsnit 2.3.1 ({_}Anvendelse af queries{_}). Har man derimod behov for at modtage hændelser i nær realtid, fordi man for eksempel skal igangsætte en proces baseret på ændringer i registerdata, kan man i stedet abonnere på hændelser, beskrevet i afsnit 2.3.2 ({_}Abonnement på hændelser{_}).
Autentifikation og autorisation for at kunne sende forespørgsler til GraphQL-tjenesterne er beskrevet i *\[C0200-ENTITETSBASEREDE-GRAPHQL\]{*}. |
Ved anvendelse af queries for at modtage hændelser, sendes en query afsted mod endepunktet for det ønskede registers GraphQL-tjeneste. Når anvenderen sender en query, får anvenderen hændelser tilbage, der indeholder metadata om ændringer i registerets data. Hvor mange hændelser der bliver returneret, og hvilke entiteter det omhandler kommer an på den sendte query. Queries returnerer alle hændelser for et register, inklusive historiske. EventID kan bruges for at filtrere på nye hændelser gennem at lave et "greater than" filter på den sidste kendte EventID. Filtrering beskrives yderligere i afsnit 4.2 (Mulige filtreringer). Dette flow er afbilledet i Figur 2.

Figur 2: Flow for modtagelse af hændelser via queries
GraphQL-abonnementer på hændelser benytter Server-Sent Events (SSE) teknologi, som muliggør en vedvarende forbindelse mellem server og klient (anvenders egne løsninger). Når en klient sender en GraphQL forespørgsel for at abonnere på hændelser, oprettes der til serveren, en åben forbindelse, som venter på nye data.
Hvis der er hændelser tilgængelige der opfylder de kriterier opsat i abonnementet, returneres de næsten øjeblikkeligt via SSE. Ellers holdes forbindelsen åben, indtil forbindelsen rammer tidsgrænsen på 10 minutter, eller brugeren selv lukker den. Klienten kan derefter straks åbne en ny forbindelse og fortsætte med at vente på opdateringer, hvilket sikrer næsten realtids-opdateringer. Afsendelsesfrekvensen for hændelser vil som udgangspunkt ligge på 30 sekunder for alle registre, dvs. at der maksimum vil gå 30 sekunder, fra en hændelse er oprettet i Datafordelerens database, til den publiceres til anvendere. Dette flow er afbilledet i Figur 3.
Abonnementsforespørgsler ligner almindelige queries, men uden pagingsegenskaber, da kun én hændelse returneres ad gangen, når nye data detekteres. Abonnementer understøtter de samme filtreringsmuligheder som queries, hvilket giver anvender kontrol over hvilke hændelser, der skal modtages. Filtrering beskrives i afsnit 4.2 (Mulige filtreringer), og oprettelse af abonnement på hændelser beskrives i afsnit 4.5 (Opret abonnement).

Figur 3: Flow for modtagelse af hændelser via abonnement
For at illustrere de praktiske anvendelsesmuligheder af Datafordelerens hændelsessystem, præsenteres her en række konkrete forretningsscenarier fra forskellige brancher og sektorer. Disse eksempler viser, hvordan organisationer kan udnytte hændelser til at automatisere forretningsprocesser, sikre datakvalitet og optimere deres it-systemer.
Scenarierne spænder fra offentlige myndigheder, der skal sikre regeloverholdelse og effektiv sagsbehandling, til private virksomheder der bruger realtidsdata til at forbedre kundeservice og risikostyring. Hvert scenarie beskriver både det forretningsmæssige behov og den konkrete tekniske implementering ved hjælp af moderniserede hændelser.
Disse eksempler kan bruges som inspiration til at identificere lignende anvendelsesmuligheder i din egen organisation og som vejledning til implementering af hændelsesbaserede løsninger.
Scenarie: En kommune skal automatisk opdatere deres byggesagssystem, når nye bygninger registreres, eller eksisterende bygninger ændres i BBR.
Implementering:
Abonner på BBR_Bygning hændelser med eventaction: \["i", "u"\] |
Scenarie: SKAT skal overvåge virksomhedsændringer for korrekt selskabsbeskatning og momsregistrering.
Implementering:
Scenarie: En it-leverandør skal holde flere kundesystemer synkroniserede med centrale registre.
Implementering: