Skip to main content

Background jobs, TickerQ en periodieke verwerking

18.1 Doel van dit hoofdstuk

Dit hoofdstuk beschrijft hoe OefenHub achtergrondverwerking, periodieke verwerking, uitgestelde acties en retrybare technische verwerking uitvoert. De uitwerking sluit aan op de middel-zware modulaire monoliet uit Technisch Ontwerp: architectuuroverzicht en solution-opbouw en de dependency- en modulegrenzen uit Technisch Ontwerp: applicatielagen, projectstructuur en dependency-richting.

Background jobs worden gebruikt voor verwerking die niet betrouwbaar of wenselijk direct in de gebruikersrequest hoeft plaats te vinden, maar wel technisch herleidbaar, begrensd, idempotent en beheerbaar moet zijn. Voorbeelden zijn periodieke opschoning, verwerken van verlopen termijnen, retrybare notificatieverwerking, geplande technische onderhoudstaken en domeinacties die bewust buiten de directe gebruikersflow worden geplaatst.

Dit hoofdstuk introduceert geen nieuwe functionele eisen. Functionele regels over bijvoorbeeld verlopen relatie-uitnodigingen, testrun-opruiming, meldingenheropentermijnen, systeemcommunicatie of PDF-cleanup blijven afkomstig uit Functioneel Ontwerp, Software Requirements Specification en database-informatie. Dit hoofdstuk beschrijft hoe zulke regels technisch uitgevoerd en bewaakt worden.

18.2 Ontwerpuitgangspunten

Voor background jobs gelden de volgende ontwerpuitgangspunten.

UitgangspuntTechnische betekenis
Eén applicatie, één databaseBackground jobs draaien binnen dezelfde deploybare OefenHub-applicatie en gebruiken dezelfde relationele database.
TickerQ als schedulerTickerQ wordt gebruikt voor planning, uitvoering, retrybeleid en periodieke verwerking.
Eigen schedulingmoduleOefenHub.Scheduling is eigenaar van de technische joblifecycle.
Domeineigenaarschap blijft intactDe businesslogica van een job blijft in de module die functioneel eigenaar is van de actie.
Geen externe message brokerRabbitMQ, Azure Service Bus of vergelijkbare message brokers zijn geen uitgangspunt voor de eerste technische baseline.
Persistente jobstatusEen applicatieherstart mag geplande, lopende of gefaalde jobs niet onzichtbaar of onherleidbaar maken.
Begrensde retriesRetrybare acties worden niet oneindig opnieuw geprobeerd.
IdempotentieOpnieuw uitvoeren van een job mag geen dubbele of corrupte domeinmutaties veroorzaken.
HerleidbaarheidIedere jobuitvoering moet via correlation-id, job-id en domeinlogging te reconstrueren zijn.
Interne beheerbaarheidJobstatussen en gefaalde jobs moeten intern inzichtelijk en waar nodig herstelbaar zijn.

18.3 Project- en schema-afbakening

OefenHub.Scheduling is het technische project voor background jobs, TickerQ-integratie en periodieke verwerking.

src/
OefenHub.Scheduling/
Contracts/
Data/
Models/
Services/
Extensions/

Wanneer TickerQ persistence en/of aanvullende schedulingtabellen nodig zijn, gebruikt dit project een eigen DbContext en schema.

OnderdeelKeuze
ProjectOefenHub.Scheduling
DbContextSchedulingDbContext, indien eigen persistente jobmetadata nodig is naast TickerQ-tabellen
Schemascheduling
TickerQ-tabellenBij voorkeur onder het schema scheduling, mits TickerQ dit ondersteunt
ConnectionstringDezelfde applicatieconnectionstring als de overige modules
WebinterfaceTickerQ-dashboard of webinterface alleen intern beschikbaar maken

Het schedulingproject wordt geen eigenaar van domeindata. Het bewaart technische jobstatus, planning, pogingen, fouten en correlation-informatie. De feitelijke domeinmutatie wordt altijd uitgevoerd via een publiek contract van de betreffende domeinmodule.

18.4 Verantwoordelijkheidsverdeling

De kernregel is dat scheduling eigenaar is van de technische lifecycle van jobs, terwijl domeinmodules eigenaar blijven van de inhoudelijke actie.

VerantwoordelijkheidEigenaar
Bepalen dat een job nodig isDomeinmodule of technische infrastructuurlaag die de situatie detecteert
Job aanvragenDomeinmodule via scheduling-contract
Job persistent registrerenOefenHub.Scheduling / TickerQ
Job plannenOefenHub.Scheduling / TickerQ
Retryconfiguratie toepassenOefenHub.Scheduling
Jobuitvoering startenOefenHub.Scheduling
Domeinactie uitvoerenFunctioneel eigenaar via publiek contract
Domeinregels validerenFunctioneel eigenaar
Technische jobstatus bijwerkenOefenHub.Scheduling
Technische jobfout registrerenOefenHub.Scheduling, met correlation naar domeinlogging
Domeinlogging/history vastleggenFunctioneel eigenaar van de actie
Failed-job beheerbaar makenOefenHub.Scheduling

Voorbeeld: wanneer OefenHub.Communication een uitgesteld te verzenden of opnieuw te proberen systeembericht wil verwerken, maakt Communication geen eigen scheduler. De module vraagt via het schedulingcontract een job aan. Wanneer de job triggert, roept Scheduling een publiek contract van Communication aan. Communication bepaalt of het bericht inhoudelijk nog verzonden mag worden en voert de domeinmutatie uit.

18.5 Jobtypen

OefenHub onderscheidt meerdere technische jobtypen. Deze indeling is bedoeld om retrybeleid, logging en beheerbaarheid per soort verwerking helder te houden.

JobtypeOmschrijvingVoorbeeld
Periodieke controlejobJob die op vaste interval kandidaten zoekt en verwerktVerlopen meldingenheropentermijnen controleren
Delayed jobJob die éénmalig op een gepland moment uitgevoerd wordtTijdelijke export uitgesteld opruimen
Retrybare vervolgactieVervolgactie na eerdere bronmutatie die bij technische fout opnieuw geprobeerd mag wordenRetry van een communicatieactie
Maildelivery jobUitgestelde of retrybare maildispatch via de geconfigureerde mailproviderUitnodigingsmail of notificatiemail opnieuw aanbieden
OnderhoudsjobTechnische of beheergerichte periodieke taakOpruimen van achtergebleven testruns
HersteljobExpliciet beheer- of supportgestuurd herstel van eerder gefaalde technische verwerkingFailed job opnieuw aanbieden na analyse

Een jobtype is geen vrij tekstveld zonder betekenis. Per jobtype moet technisch vastliggen welk contract wordt aangeroepen, welke payload verwacht wordt, welk retrybeleid geldt en welke fouten tot definitieve failed-status leiden.

18.5.1 Maildelivery jobs

Maildelivery jobs zijn technische jobs voor e-mailverwerking die door een domeinmodule of door Communication worden aangevraagd wanneer e-maildispatch niet direct of niet betrouwbaar binnen de gebruikersflow moet worden uitgevoerd.

OnderdeelRegel
Eigenaarschap joblifecycleOefenHub.Scheduling bewaakt status, retries, pogingenteller, foutregistratie en dashboardzichtbaarheid.
Eigenaarschap inhoudOefenHub.Communication of de veroorzakende domeinmodule bepaalt de mailinhoud, ontvangercontext en functionele geldigheid.
ProviderintegratieVia OefenHub.Infrastructure en veilige configuratie.
IdempotentieIedere maildelivery job heeft een idempotency key zodat retry geen dubbele domeinmutatie veroorzaakt.
FalenNa begrensde retries eindigt de job in beheerbare failed-status met correlation-id en laatste foutcategorie.
HerstelHerstart of handmatige retry mag alleen opnieuw dispatchen wanneer de onderliggende domeinactie nog geldig is.

Een maildelivery job mag geen workaround zijn voor een ongeldige bronmutatie. Wanneer mail de enige functionele ingang voor een gebruiker is, bepaalt de workflow of de mailaanvraag onderdeel is van de kritieke transactie.

18.6 Job lifecycle

Een job doorloopt technisch een expliciete lifecycle. De exacte statusnamen kunnen worden afgestemd op TickerQ, maar de conceptuele lifecycle is als volgt.

StatusBetekenis
ScheduledJob is geregistreerd en wacht op uitvoering.
ProcessingJob wordt op dit moment uitgevoerd.
SucceededJob is succesvol voltooid.
RetryScheduledJob is gefaald maar wordt opnieuw geprobeerd binnen het retrybeleid.
FailedJob is definitief gefaald of handmatig in failed-status geplaatst.
CancelledJob is bewust geannuleerd voordat succesvolle uitvoering nodig of toegestaan was.

Een job mag niet stilzwijgend verdwijnen. Ook wanneer TickerQ intern eigen statussen gebruikt, moet OefenHub voldoende technische en functionele informatie bewaren om de uitvoering te reconstrueren.

18.7 Jobaanvraag via contract

Domeinmodules maken jobs niet rechtstreeks aan via TickerQ-implementatiedetails. Zij gebruiken een publiek schedulingcontract.

Voorbeeld van een conceptueel contract:

public interface ISchedulingJobService
{
Task<ScheduledJobReference> ScheduleAsync(
ScheduleJobRequest request,
CancellationToken cancellationToken = default);
}

Voorbeeld van een aanvraagmodel:

public sealed class ScheduleJobRequest
{
public required string JobType { get; init; }
public required string PayloadJson { get; init; }
public required string CorrelationId { get; init; }
public required string TriggeredByModule { get; init; }
public Guid? TriggeredByUserId { get; init; }
public string? TriggeredByRoleContext { get; init; }
public DateTimeOffset ExecuteAfterUtc { get; init; }
public string? RetryPolicyKey { get; init; }
}

Dit voorbeeld is geen verplichte definitieve C#-implementatie, maar legt het technische principe vast: domeinmodules vragen jobs aan via een contract en geven voldoende context mee voor uitvoering, logging, retrybeleid en herleidbaarheid.

18.8 Jobuitvoering via domeincontract

Wanneer TickerQ een job uitvoert, verwerkt OefenHub.Scheduling de job niet door rechtstreeks domeintabellen of domeinentities te muteren. De scheduler roept een publiek contract van de eigenaarmodule aan.

Voorbeeld:

public interface IPendingMessageDeliveryJobHandler
{
Task<DomainJobResult> ExecuteAsync(
PendingMessageDeliveryJobPayload payload,
JobExecutionContext context,
CancellationToken cancellationToken = default);
}

De handler leeft in de domeinmodule, bijvoorbeeld OefenHub.Communication. De scheduler is alleen verantwoordelijk voor het laden van de job, het doorgeven van context, het vastleggen van technische uitvoering en het bepalen van retry of failed-status.

18.9 Transaction boundaries en consistentie

Background jobs mogen niet worden gebruikt om onveilige halve functionele toestanden te normaliseren. Per workflow moet expliciet bepaald worden welke stappen kritiek zijn voor de functionele uitkomst.

SituatieBeleid
De actie is zonder stap B functioneel ongeldigStap A en B horen in dezelfde transaction boundary of dezelfde kritieke workflow.
De vervolgactie is alleen notificerend of afgeleidDe vervolgactie mag retrybaar buiten de gebruikersflow plaatsvinden.
Een systeembericht is de enige ingang voor de gebruikerHet systeembericht is functioneel kritiek en mag niet automatisch als niet-kritiek worden behandeld.
Een job raakt meerdere domeinenPer jobtype vastleggen of atomische uitvoering, compensatie of failed-status nodig is.
Falen kan door beheer veilig hersteld wordenFailed-status met beheerbare herstelactie is toegestaan.
Falen leidt tot onherstelbare of misleidende dataDe stap moet als kritiek behandeld worden.

Scheduling mag dus zowel niet-kritieke vervolgacties als kritieke geplande workflows ondersteunen, maar het Technisch Ontwerp beschouwt deze niet als hetzelfde patroon.

18.9.1 Kritieke bronmutaties

Kritieke bronmutaties die samen de functionele uitkomst van één actie bepalen, worden niet losjes als meerdere onafhankelijke jobs achter elkaar gezet wanneer falen van stap twee de uitkomst van stap één ongeldig maakt.

Voorbeeld: als een relatie-uitnodiging alleen via een systeembericht bereikbaar is voor de ontvanger, dan kan het aanmaken van de uitnodiging en het aanmaken van het systeembericht onderdeel zijn van dezelfde kritieke workflow. In dat geval mag de uitnodiging niet succesvol lijken wanneer het bericht niet is aangemaakt.

18.9.2 Niet-kritieke vervolgacties

Niet-kritieke vervolgacties mogen buiten de directe request plaatsvinden wanneer zij:

  • idempotent zijn;
  • begrensd retrybaar zijn;
  • bij falen zichtbaar worden in technische logging of beheer;
  • geen ongeldige functionele bronstatus achterlaten;
  • op een volgend moment opnieuw opgebouwd of hersteld kunnen worden.

Voorbeelden zijn tellerprojecties, readmodelverversing, badges, technische cleanup of informatieve notificaties die niet de enige functionele ingang vormen.

18.10 Retrybeleid

Retry is een hulpmiddel, geen vervanging voor goede transactionele afbakening. Iedere retrybare job heeft een expliciet retrybeleid. Retrybare verwerking blijft binnen TickerQ en de bestaande modulaire monoliet; zij introduceert geen externe message broker of los workflowplatform.

AspectRegel
Maximum aantal pogingenPer jobtype configureren; geen oneindige retries.
BackoffPer jobtype bepalen, bijvoorbeeld vaste interval of oplopende interval.
Idempotency keyVereist bij acties waarbij dubbele uitvoering schade kan veroorzaken.
FoutclassificatieOnderscheid tussen tijdelijke technische fout en definitieve functionele fout.
Failed-statusNa overschrijden van retrybeleid blijft de job zichtbaar als gefaald.
BeheeractieFailed jobs moeten intern analyseerbaar en waar toegestaan opnieuw aan te bieden zijn.

Voorbeeld van retryclassificatie:

FouttypeRetry?Voorbeeld
Tijdelijke database-lock of timeoutJaVerwerking wordt via een expliciet technisch ontwerpbesluit opnieuw geprobeerd.
Tijdelijke externe render-/bestandsfoutJa, begrensdPDF-cleanup of tijdelijke exportverwerking.
Ongeldige payloadNeeJob gaat naar Failed voor analyse.
Domeinobject niet meer geldigMeestal neeUitnodiging verlopen of relatie beëindigd.
Autorisatiecontext ongeldigNee, tenzij expliciet herstelbaarJob mag geen rechten omzeilen.

18.10.1 Retrydefaults per jobtype

De V1.0-baseline gebruikt retrydefaults per jobtype. Deze defaults zijn bewust licht gehouden en mogen per concrete job alleen worden aangescherpt of verruimd wanneer de jobhandler idempotent is en de afwijking expliciet in configuratie, code of documentatie is vastgelegd. Finetuning per concrete job blijft toegestaan tijdens implementatie; het bestaan van finetuning heropent dit ontwerpbesluit niet.

JobtypeMaximaal aantal pogingenDelay/backoffFailed-status en beheeractie
Periodieke controlejob1 retry na de initiële pogingKorte vaste delay, bijvoorbeeld 5 minutenDaarna Failed of batchfout zichtbaar maken; de volgende periodieke run mag dezelfde kandidaten opnieuw vinden.
Onderhoudsjob1 retry na de initiële pogingKorte vaste delay, bijvoorbeeld 5 tot 15 minutenDaarna zichtbaar als failed; technisch beheer beoordeelt of handmatige retry of wachten op volgende interval passend is.
Retrybare vervolgactie3 pogingen totaalOplopend, bijvoorbeeld 5 minuten, 30 minuten, 2 uurDaarna failed met correlation-id; handmatige retry alleen wanneer de onderliggende domeinactie nog geldig is.
Delayed job3 pogingen totaalOplopend, bijvoorbeeld 5 minuten, 30 minuten, 2 uurDaarna failed; opnieuw plannen vereist een nieuwe geldige aanvraag of beheeractie.
Maildelivery job5 pogingen totaalOplopend, bijvoorbeeld 5 minuten, 15 minuten, 1 uur, 6 uur, 24 uurDaarna failed en zichtbaar voor technisch beheer; mail wordt niet onbeperkt opnieuw aangeboden.
Hersteljob1 poging, tenzij expliciet anders gekozenGeen automatische backoff of maximaal één korte retryBij falen opnieuw analyseren; hersteljobs zijn beheer-/supportgestuurd en mogen geen automatische retryloop worden.
Readmodel- of cache-refresh job3 pogingen totaalOplopend, bijvoorbeeld 1 minuut, 5 minuten, 15 minutenDaarna failed of rebuild vereist; brondata blijft leidend en afgeleide projectie mag opnieuw worden opgebouwd.

Regels:

  • het aantal pogingen telt de eerste uitvoering mee;
  • functionele fouten, ongeldige payloads, verlopen domeinobjecten en ontbrekende autorisatiecontext leiden niet tot blind retryen;
  • periodieke controlejobs gebruiken weinig retries, omdat de volgende interval gemiste kandidaten opnieuw kan selecteren;
  • maildelivery krijgt meer retries, omdat externe mailproviders tijdelijk onbeschikbaar kunnen zijn;
  • iedere retrybare job heeft een idempotency-afspraak voordat retry in productie wordt geactiveerd;
  • iedere definitief gefaalde job bevat minimaal jobtype, attemptnummer, correlation-id, foutcategorie en laatste fouttijdstip;
  • concrete jobhandlers mogen lagere retrygrenzen gebruiken wanneer dat veiliger is;
  • ruimere retrygrenzen dan deze baseline vereisen een expliciete technische motivatie.

18.11 Idempotentie

Iedere jobhandler moet veilig kunnen omgaan met herhaalde uitvoering. Dat is nodig omdat retries, applicatieherstarts, timeouts of onduidelijke uitvoeringsstatus kunnen leiden tot opnieuw uitvoeren.

Voorbeelden van idempotentie-afspraken:

ActieIdempotentieafspraak
Systeembericht aanmakenGebruik een idempotency key of bronverwijzing zodat hetzelfde bericht niet dubbel ontstaat.
Testruns opruimenAlleen records verwerken die nog aan de selectiecriteria voldoen.
Heropentermijn verwerkenAlleen actuele sluitcontext verwerken; inmiddels geregistreerde heropeningen uitsluiten.
Readmodel verversenUpsert of rebuild gebruiken in plaats van blind dupliceren.
Tijdelijke bestanden verwijderenOntbrekend bestand beschouwen als reeds opgeschoond, niet als functionele fout.

Idempotentie hoort bij de domeinhandler, omdat alleen de eigenaarmodule weet wanneer dubbele uitvoering functioneel schadelijk is.

18.12 Correlation, logging en technische herleidbaarheid

Jobuitvoering moet domeinoverstijgend herleidbaar zijn. Iedere job en iedere domeinactie die door een job wordt gestart, gebruikt dezelfde correlation-id.

Minimaal vast te leggen technische context:

VeldBetekenis
CorrelationIdVerbindt request, domeinactie, jobaanvraag, jobuitvoering en domeinlogging.
JobIdTechnische identifier van de geplande job.
JobTypeType verwerking dat wordt uitgevoerd.
AttemptNumberHuidige poging binnen het retrybeleid.
TriggeredByModuleModule die de job heeft aangevraagd of gepland.
TriggeredByUserIdGebruiker die de oorspronkelijke actie veroorzaakte, indien van toepassing.
TriggeredByRoleContextRolcontext van de oorspronkelijke actie, indien van toepassing.
StartedAtUtcStartmoment van deze poging.
CompletedAtUtcSuccesvol eindmoment.
FailedAtUtcFoutmoment bij mislukking.
LastErrorCodeTechnisch of functioneel fouttype.
LastErrorMessageBeperkte foutinformatie zonder gevoelige payloads of tokens.

Logging mag geen wachtwoorden, tokens, volledige identity-providerpayloads, onnodige persoonsgegevens of volledige antwoordpayloads van oefeningen bevatten. Wanneer een job gevoelige domeindata verwerkt, wordt alleen de noodzakelijke technische context gelogd.

18.13 Security en autorisatie bij jobs

Jobs draaien server-side en mogen geen clientstate, routeparameters of UI-context vertrouwen. Wanneer een job namens of naar aanleiding van een gebruikeractie draait, moet de relevante server-side context in de payload of jobcontext zijn vastgelegd en opnieuw door de domeinhandler worden beoordeeld.

OnderwerpRegel
AutorisatieJobs mogen geen domeinregels of autorisatiecontroles omzeilen.
RolcontextIndien relevant wordt de oorspronkelijke rolcontext als snapshot meegegeven.
GebruikercontextTriggeredByUserId is contextinformatie, geen automatisch autorisatiebewijs.
PayloadPayload bevat alleen noodzakelijke identifiers en parameters.
SecretsSecrets worden niet in jobpayloads opgeslagen.
DashboardtoegangTickerQ-dashboard is alleen intern en beheerbaar beschikbaar.
Handmatige retryHandmatige retry vereist beheercontext en logging.

Als een job bij uitvoering ontdekt dat de domeincontext niet langer geldig is, moet de handler een expliciet resultaat teruggeven, bijvoorbeeld Cancelled, NoLongerApplicable of Failed, afhankelijk van de aard van de job.

18.14 TickerQ-dashboard en interne beheerbaarheid

Wanneer TickerQ een webinterface of dashboard biedt voor jobinzage, wordt deze gebruikt als interne beheerfunctie. Deze interface is niet publiek bereikbaar.

AspectRegel
BeschikbaarheidAlleen intern, bijvoorbeeld via beheeromgeving, intern netwerk of afgeschermde route.
AutorisatieAlleen beheerder- of technische beheercontext.
Zichtbare informatieGeen gevoelige payloads, tokens of persoonsgegevens tonen tenzij functioneel noodzakelijk en toegestaan.
Handmatige actiesRetry, annuleren of markeren als afgehandeld alleen met logging.
AuditbaarheidHandmatige beheeracties rond jobs worden technisch herleidbaar gelogd.

Het dashboard is bedoeld voor technische analyse en herstel, niet als gebruikersgerichte functionaliteit.

18.15 Periodieke jobs per domein

De onderstaande tabel geeft de eerste technische ordening van bekende periodieke of achtergrondverwerkingen. De exacte jobnamen en intervallen worden bij implementatie afgestemd op de definitieve domein- en databaseuitwerking.

DomeinVerwerkingTypeEigenaar uitvoeringSchedulingrol
RelationshipsVerlopen relatie-uitnodigingen markerenPeriodieke controlejobOefenHub.RelationshipsTriggert interval en bewaakt status
PracticeAchtergebleven docent-testruns opruimenPeriodieke onderhoudsjobOefenHub.PracticeTriggert interval en registreert fouten
SupportVerlopen heropentermijnen verwerkenPeriodieke controlejobOefenHub.SupportTriggert interval; geen losse job per ticket
CommunicationRetrybare communicatieacties verwerkenRetrybare vervolgactieOefenHub.CommunicationBewaakt pogingen en failed-status
ReportingTijdelijke PDF-/exportbestanden opruimenPeriodieke onderhoudsjobOefenHub.ReportingTriggert interval en registreert technische fouten
AdminVerlopen systeemnotificaties controleren indien nodigPeriodieke controlejobOefenHub.AdminAlleen indien technische verwerking nodig is

Niet iedere functionele datum vereist een losse scheduled job. Waar veel records op vergelijkbare criteria verlopen, heeft een periodieke idempotente controlejob de voorkeur boven één losse TickerQ-job per record.

18.16 Verlopen meldingenheropentermijnen

Voor meldingen geldt expliciet dat het definitief gebruikersgericht sluiten na verlopen heropentermijn niet wordt ingericht als losse TickerQ-taak per melding. De technische verwerking zoekt periodiek naar kandidaten die op dat moment aan de actuele databasecriteria voldoen.

Technische aanpak:

  1. OefenHub.Scheduling triggert periodiek de supportjob.
  2. OefenHub.Support zoekt gesloten tickets met een actuele sluitregistratie waarvan ReopenDeadlineUtc verlopen is.
  3. Tickets die inmiddels zijn heropend, geaccepteerd of geen actuele sluitcontext meer hebben, worden uitgesloten.
  4. Per kandidaat wordt idempotent bepaald of een compacte historyregel nodig is.
  5. Fout bij één kandidaat blokkeert de verwerking van andere kandidaten niet.
  6. De job rapporteert aantal gevonden, verwerkt, overgeslagen en gefaalde kandidaten.

Deze aanpak voorkomt een grote hoeveelheid losse jobs en vangt gemiste of vertraagde uitvoeringen automatisch op bij een volgende run.

18.17 Verlopen relatie-uitnodigingen

Relatie-uitnodigingen verlopen op basis van domeinregels uit het relatiedomein. De scheduler voert geen relatiebeslissingen uit, maar triggert een publieke handler van OefenHub.Relationships.

Technische aandachtspunten:

  • alleen uitnodigingen met status Pending komen in aanmerking;
  • uitnodigingen die al Accepted, Rejected of Expired zijn, worden overgeslagen;
  • verwerking is idempotent;
  • verlopen verwijdert geen uitnodigingshistorie;
  • gekoppelde systeemberichten worden niet hard verwijderd door deze job;
  • audit/history blijft binnen het relatiedomein.

18.18 Testrun-opruiming

Docenttestruns mogen technisch tijdelijke runstructuren gebruiken, maar horen niet in reguliere leerlinggeschiedenis of permanente resultaten terecht te komen. Opruiming van achtergebleven testruns wordt periodiek uitgevoerd door OefenHub.Practice.

Technische aandachtspunten:

  • alleen runs met testmarkering komen in aanmerking;
  • afgeronde of verlaten testcontexten worden volgens bewaartermijn of technische criteria opgeschoond;
  • reguliere leerlingruns worden nooit door deze job verwijderd;
  • cleanup is idempotent;
  • fouten bij één run blokkeren andere kandidaten niet;
  • logging bevat geen volledige vraag-/antwoordpayload tenzij dit voor technische analyse expliciet en veilig noodzakelijk is.

18.19 Tijdelijke export- en PDF-cleanup

PDF-exportbestanden zijn tijdelijke output. Bij opnieuw downloaden wordt een PDF opnieuw opgebouwd uit databasegegevens, snapshots en modulepresentatie, zoals verder uitgewerkt in 16 PDF-export met QuestPDF.

Opruiming van tijdelijke bestanden wordt als technische onderhoudsjob ingericht.

AspectRegel
BrondataDatabase en snapshots blijven bron; tijdelijke bestanden niet.
Tijdelijke opslagOefenHub:Reporting:TempExportPath, buiten webroot.
CleanupeligibleStandaard CreatedAtUtc + 24 uur.
PlanningMinimaal iedere 6 uur uitvoeren.
Hard maximumBestanden ouder dan 48 uur als cleanupachterstand loggen/monitoren.
Ontbrekend bestandBeschouwen als reeds opgeschoond wanneer de databasecontext dat ondersteunt.
Fout bij verwijderenBegrensd retrybaar wanneer het om tijdelijke technische fout gaat.
Gevoelige inhoudTijdelijke bestanden mogen niet langer blijven staan dan technisch nodig.
LoggingBestandsnaam of technische referentie loggen, geen volledige exportinhoud.

18.20 Scheduling-configuratie

Schedulingconfiguratie wordt expliciet per jobtype vastgelegd. De configuratie mag in code, appsettings of beheerbare technische configuratie worden ondergebracht afhankelijk van de aard van de job.

ConfiguratieVoorbeeld
JobtypeSupport.ProcessExpiredReopenDeadlines
IntervalElke 12 uur
RetrybeleidMaximaal 3 pogingen met oplopende wachttijd
TimeoutMaximale uitvoeringstijd per poging
ConcurrencyEén instance tegelijk voor dezelfde jobfamilie indien nodig
DashboardzichtbaarheidIntern zichtbaar
PayloadtypeNaam van het verwachte payloadmodel
HandlercontractPubliek contract van eigenaarmodule

Functionele waardes zoals bewaartermijnen of heropentermijnen blijven domeinconfiguratie of functionele instellingen. Schedulingconfiguratie bepaalt wanneer en hoe verwerking draait, niet wat de domeinregel inhoudelijk betekent.

18.21 Foutafhandeling

Foutafhandeling bestaat uit drie lagen.

LaagVerantwoordelijkheid
DomeinhandlerGeeft domeinresultaat terug, valideert actuele context en voorkomt corrupte mutaties.
SchedulingRegistreert poging, fout, retry of failed-status.
Logging/monitoringMaakt technische analyse en beheerherstel mogelijk.

Een fout bij één kandidaat in een batch mag de verwerking van andere kandidaten niet blokkeren wanneer de kandidaten onafhankelijk verwerkt kunnen worden. De job moet dan een gedeeltelijk resultaat kunnen rapporteren.

Voorbeeld batchresultaat:

Found: 124
Processed: 121
Skipped: 2
Failed: 1
CorrelationId: 9b3d...

Bij definitieve fout wordt de job of kandidaat niet stilzwijgend genegeerd. Er moet een traceerbare failed-status of foutlog aanwezig zijn.

18.22 Concurrency en locking

Periodieke jobs kunnen overlappen door trage uitvoering, herstart of meerdere applicatie-instances. Daarom moet per jobtype worden bepaald of gelijktijdige uitvoering toegestaan is.

ScenarioBeleid
Eén globale verwerking tegelijkGebruik TickerQ-locking of database-locking per jobtype.
Parallel per kandidaat toegestaanGebruik kandidaatniveau-locking of idempotente verwerking.
Zelfde record kan door gebruiker wijzigenHercontroleer actuele status vlak voor mutatie.
Job opnieuw gestart na crashGebruik idempotentie en statuscriteria om dubbele verwerking te voorkomen.

Een job mag niet vertrouwen op gegevens die alleen aan het begin van de uitvoering zijn gelezen wanneer de domeinstatus intussen gewijzigd kan zijn. Vlak voor mutatie voert de domeinhandler opnieuw de relevante status- en autorisatiecontrole uit.

18.23 Relatie met readmodels en badges

Readmodels, tellers en badges zijn vaak geschikt voor achtergrondverwerking of retrybare naverwerking, mits zij geen functionele bron van waarheid zijn. Details over readmodels en materialisatie staan in 17 Readmodels, tellers, badges, caching en materialisatie.

Technische regels:

  • readmodelverversing mag retrybaar zijn wanneer het readmodel herbouwbaar is;
  • badge-updates mogen achterlopen wanneer de onderliggende bronstatus correct is;
  • zichtbare tellerupdates mogen geen autorisatiebron worden;
  • falende readmodeljobs moeten zichtbaar zijn voor technische analyse;
  • bij twijfel moet het scherm kunnen terugvallen op bronqueries of een veilige lege/vertragingstoestand.

18.24 Relatie met logging, monitoring en beheer

Jobuitvoering raakt direct aan technische foutafhandeling en monitoring. De verdere logginguitwerking staat in 19 Logging, audit, securitylogging en technische foutafhandeling. Operationele inrichting, backup, restore en interne beheerbaarheid staan in 21 Beheerbeleid, monitoring, backup, restore en operatie.

Voor jobs gelden minimaal deze operationele verwachtingen:

  • failed jobs zijn intern zichtbaar;
  • langdurig falende jobtypes veroorzaken een beheer- of monitoringalert;
  • retryloops zijn begrensd;
  • technische foutinformatie is voldoende voor analyse;
  • gevoelige payloads worden niet onnodig getoond of gelogd;
  • handmatige herstelacties zijn herleidbaar.

18.25 Teststrategie voor jobs

Jobs worden niet uitsluitend via end-to-endtests gevalideerd. Testdekking wordt per laag ingericht.

TesttypeDoel
Unit tests domeinhandlerDomeinregels, idempotentie en foutclassificatie testen.
Scheduling integration testsJobregistratie, payloadbinding en handlerresolving testen.
Retry testsPogingenteller, backoff en failed-status testen.
Concurrency testsDubbele uitvoering en lockinggedrag testen waar relevant.
Architecture testsVoorkomen dat Scheduling rechtstreeks domeinentities of DbContexts van andere modules gebruikt.
Smoke testsControleren dat periodieke jobs na deployment geregistreerd zijn.

De algemene teststrategie staat in 23 Teststrategie, acceptatieherleidbaarheid en kwaliteitsgrenzen.

18.26 Implementatieverificaties

Bij implementatie van TickerQ en scheduling moeten minimaal de volgende punten concreet worden gecontroleerd:

  • of TickerQ-tabellen onder schema scheduling geplaatst kunnen worden;
  • hoe TickerQ migration/persistence wordt ingericht naast modulemigrations;
  • hoe de TickerQ-webinterface intern wordt afgeschermd;
  • dat retrybeleid per jobtype conform de vastgelegde defaultmatrix wordt geconfigureerd;
  • hoe handmatige retry of annulering wordt gelogd;
  • hoe jobpayloads worden gevalideerd en beperkt;
  • hoe correlation-id wordt doorgegeven naar domeinhandlers;
  • hoe meerdere applicatie-instances jobconcurrency voorkomen of veilig afhandelen;
  • hoe failed jobs operationeel zichtbaar worden;
  • hoe backup/restore omgaat met geplande en reeds uitgevoerde jobs.

Deze punten zijn technische implementatiecontroles binnen het Technisch Ontwerp. Wanneer één van deze controles leidt tot een structurele ontwerpwijziging, moet het relevante hoofdstuk van het Technisch Ontwerp en zo nodig database-informatie worden bijgewerkt.