Omdat API documentatie een optionele extra functionaliteit was, heb ik https://springdoc.org/ toegevoegd. Met Spring boot 3 en later kreeg ik deze docs alleen werkend met maven als build systeem.
Voor het voorraadbeheer heb ik voor een in memory HSQL database gekozen. Simpelweg omdat deze met een dependency is toe te voegen.
Het eerste wat ik deed voor deze opdracht was het datamodel voor de database maken. De opdracht spreekt over CRUD van productvoorraad. Om een productvoorraad goed te kunnen simuleren heb ik drie tabellen gemaakt:
Een STORES tabel met daarin de vier Gamma en Karwei vestigingen bij mij in de buurt.
Een PRODUCT tabel met de product informatie die het zelfde is ongeacht van de winkel.
Een STOCK kopppeltabel met het aantal exemplaren van het product, store id en product id.
Voor de eis om een artikel voor vijf minuten te kunnen reserveren, heb ik nog twee tabellen gemaakt:
Een RESERVATIONS koppeltabel. Als iemand 2 stuks van product X reserveerd, zal ik in een database transactie het aantal van het product in de STOCK tabel verminderen EN een nieuwe record in de RESERVATIONS tabel aanmaken. Dit nieuwe record heeft een timestamp die over vijf minuten verloopt.
Een ORDERS koppeltabel. Als iemand de reservatie uit de RESERVATIONS tabel binnen vijf minuten afrekent, dan wordt het een order en krijgt de consumer een order id.
Ik maak gebruik van een quartz scheduler om iedere vijf seconden in een transactie de stock van verlopen reserveringen weer vrij te geven.
De in memory database wordt bij het opstarten automatisch gevuld door de schema.sql en data.sql scripts in src/main/resources.
Een PUT call met als body {"delta": 10} naar http://localhost:8080/api/stores/0/product/2/stock laat de voorraad voor product X in winkel Y updaten. Als je een negatieve delta invoert wordt de voorraad minder. Het request zal falen als de negatieve delta de voorraad minder dan 0 laat zijn, of als er geen voorraad is.
De acties van de bovenste drie calls kan je controleren met de products call (regel 22)
Het gebruik van de reserveer API
Een POST call met als body {"productId": 0, "quantity": 2} naar http://localhost:8080/api/reservations doet, kijkt de applicatie welke van de vier winkels op zijn minst twee van het product met productId 0 op voorraad hebben. Als antwoord krijg je een nummer (reservering id) terug.
Als je binnen vijf minuten een POST naar http://localhost:8080/api/reservations/order/0 (0 is in dit geval het reservering id van de vorige call) doet haalt hij de reservering weg en maakt hij een order aan in de order tabel. Je krijgt dan terug wat je besteld hebt:
Bij het aanmaken van reserveringen sla ik reserveringen op met een expirationDate over vijf minuten van nu.
Elke vijf seconden loopt een quarts scheduler die checkt of er reserveringen zijn met een expirationDate die in het verleden ligt. Het aantal producten dat gereserveerd was voor een reservering wordt weer bij de voorraad opgeteld. Al deze queries draaien in een database transactie om race conditions te voorkomen.
Als deze applicatie in de cloud zou draaien zou ik er gewoon een endpoint voor maken wat aangeroepen wordt door een scheduler van de cloud provider.