Av Anders Ekdahl

Hantera framtida priser med Nexus

2024-06-09

Arkitektur, Composable Commerce & Tips

Pris-förändringar på e-handeln planeras ofta i förväg och schemaläggs. Antingen en förändring av listpriset eller ett kampanjpris som börjar gälla vid ett visst datum. Att få alla system att visa det nya priset vid rätt tidpunkt är en svårare utmaning än vad man kan tro, och i denna artikel går vi igenom hur man kan lösa det med Nexus.

I den föregående artikeln pratade vi om hur man kan använda Nexus för att säkra data-flödet mellan e-handeln och sök- och relevans-motorn. I denna artikel bygger vi vidare på detta genom att gå igenom hur man med Nexus kan hantera att framtida priser slår igenom på vid rätt tidpunkt. I förra artikeln gick vi igenom en del av fallgroparna med att använda t.ex. serverless-teknik och en helt event-driven arkitektur för denna synk. Framtida priser är ytterligare en fallgrop för den event-drivna arkitekturen eftersom ett sådant pris inte genererar något event när det börjar gälla. Datumet är satt sedan tidigare så e-handelsystemet kommer inte att generera en uppdatering av produkten. Det blir vi som måste hantera klockslaget som gör det nya priset aktivt.

Den bästa lösningen på detta problem är att se till att alla ens system kan hantera datum-styrda priser och att denna datum-styrning kan synkas i förväg så att när en tidpunkt för ett nytt pris passerar så behöver ingen synk ske, det nya priset blir bara automatiskt tillgängligt överallt. Men det är sällan alla system och i synnerhet en sök- och relevans-motor kan hantera detta.

Ofta kan man indexera lite vilken data som helst till en sökmotor så ett alternativ är att skicka in framtida priser till sökmotorn och sen låta frontend lista ut vilket pris det är som ska visas. Det största problemet med det är att det inte fungerar med sökmotorns inbyggda funktionalitet så som filtrering och sortering.

När vi i förra artikeln hade behandlat ett kö-meddelande som representerar att en produkt förändrats så markerade vi det som färdigt, och det meddelandet kommer inte att behandlas igen förrän produkten uppdateras. Men i fallet med ett framtida pris så kommer inte produkten att uppdateras och generera ett nytt event. Det framtida priset är redan bestämt. Istället blir det upp till oss att reagera vid den givna tidpunkten och skicka det nya priset till sökmotorn.

Vi börjar med att utöka meddelandet till att innehålla ett framtida pris:

[QueueMessage("product")]
public class ProductChangedQueueMessage : IQueueMessageWithId
{
    public string? Id { get; set; }
    public ProductInformation? ProductInformation { get; set; }
    public ProductPrice? Price { get; set; }
    public FuturePrice? FuturePrice { get; set; }
}

public class ProductInformation
{
    public required string? Name { get; set; }
    public required string? Description { get; set; }
}

public class ProductPrice
{
    public required decimal Price { get; set; }
    public required string Currency { get; set; }
}

public class FuturePrice : ProductPrice
{
    public required DateTime StartDateUtc { get; set; }
}

I verkligheten ser det antagligen mer komplext ut än så här. Det kan finnas flera framtida priser och det kan vara en blandning mellan framtida kampanjer eller framtida justeringar av listpriset. Men för att visa på konceptet i denna artikel håller vi det enkelt.

För att hantera detta behöver vi be Nexus att behandla samma meddelande en gång till i framtiden i vårt kö-jobb:

public class ProductQueueJob(IPreviousMessageProvider previousMessageProvider) : IScheduledQueueJob<ProductChangedQueueMessage>
{
    public string DefaultSchedule => CronSchedule.TimesPerMinute(10);

    public async Task<ProcessResults> ProcessMessageAsync(ProductChangedQueueMessage message, CancellationToken cancellationToken)
    {
        var now = DateTime.UtcNow;
        var priceToUse = message.FuturePrice?.StartDateUtc <= now ? message.FuturePrice : message.Price;
        
        await SendProductToSearchEngineAsync(message, priceToUse);
        
        DateTime? processAgainAtUtc = now < message.FuturePrice?.StartDateUtc ? message.FuturePrice.StartDateUtc : null;

        return ProcessResults.Processed(
            processAgainAtUtc: processAgainAtUtc,
            newPriority: 100
        );
    }
}

Det vi gör här är att se ifall datumet för det framtida priset har börjat gälla och isåfall skicka det framtida (som blivit nutida) priset till sökmotorn. Och ifall det framtida priset ännu inte börjat gälla så ber vi Nexus att behandla meddelandet igen vid den tidpunkt när priset börjar gälla.

Det vi också gör är att be Nexus behandla det med hög prioritet vid nästa tillfälle för att se till att dessa prisuppdateringar behandlas före andra meddelanden. Vi vill undvika att andra produktuppdateringar som inte är lika tidskritiska hamnar före i kön och skapar fördröjning innan priserna blir synliga.

Vid det tillfälle som jobbet bett att behandla meddelandet igen kommer Nexus att uppdatera meddelandets status till att hanteras av jobbet igen. Ifall många meddelanden har samma datum så kommer alla markeras för att behandlas samtidigt. När vi då ser till att vårt jobb kan behandla många meddelanden samtidigt så skapar vi minimal fördröjning mellan den tidpunkt då priset börjar gälla och att det är synligt på siten. Är det ett mindre antal produkter handlar det om ett antal sekunder. Är det en stor mängd produkter kan det ta längre tid för sökmotorn att ta emot uppdateringen men bör ändå ske inom en minut.

Vad händer om prisets datum ändras?

Schemaläggningen för det nya priset kan när som helst ändras. Kampanjen kanske tidigareläggs eller så hinner det planeras in en till kampanj som körs före den tänkta kampanjen.

Oavsett så hanteras det per automatik i Nexus. Det nya datumet blir en uppdatering av produkten vilket skickas till Nexus. Nexus-jobbet kommer att köras direkt efter att uppdateringen kommit in och ber sen Nexus att behandla meddelandet igen på det nya datumet för priset. Den tidigare schemalagda körningen av meddelandet avbryts eftersom vi nu fått ny information och schemalägger körningen vid ett annat datum istället.

På samma sätt kan många framtida priser planeras upp i förväg. Om meddelandet innehåller tio olika priser och datum kan jobbet indexera det nuvarande priset till sökmotorn och sen be Nexus köra igen när nästa pris blir aktuellt. Allt utan att någon uppdatering av produkten kommer utifrån.

Det här var del två i serien om hur man kan utnyttja Nexus för att förbättra data-flödet mellan e-handelssystemet och sökmotorn. I nästa artikel kommer vi gå igenom hur man hanterar att relaterade entiteter ändras. T.ex. att en kategori som en produkt ligger i byter namn och hur man undviker att behöva köra en full synk för att namnbytet ska slå igenom.

Låter det som att det skulle kunna hjälpa dig med dina data-flöden? Hör av dig, Nexus är gratis för alltid och du får full tillgång till koden via en open source-licens.

Anders Ekdahl

Anders är hjärnan bakom de tekniska e-handels-ramverken som tagit Nordic Nest, Lyko, NA-KD, Filippa K, Kicks, m.fl. från lovande digitala initiativ till ledande e-handelsaktörer.

I sin roll som CTO och chefsarkitekt för Sveriges främsta e-handelskonsult har han lett över 200 utvecklare till framgång. Med sin förmåga att kombinera teknik, strategi och affärsvärde har Anders en djup insikt om vad du som e-handlare behöver för att nå och överträffa dina mål.

Epost: epost

Commerce Mind

Commerce Mind är ett oberoende specialistföretag inom e-handel. Vi hjälper dig med allt från KPIer till teknik och arkitektur till processutveckling och upphandling.

Läs mer om vårt erbjudande här

Tveka inte på att kontakta oss ifall du vill röra dig snabbare.