Lärarguide · Lektion 7 av 10
Transaktioner & concurrency
Optimistic concurrency, Polly-retry, idempotency-tabell, TransactionScope för exactly-once. Det tekniskt svåraste momentet i kursen — ta tid.
Skriv ut / Spara som PDF
Mål
Studenten implementerar optimistic concurrency mot SqlStreamStores expected-version.
Studenten konfigurerar Polly-retry med exponential backoff.
Studenten förstår vad TransactionScope ger oss för exactly-once-projektioner.
Agenda
0:00
Recap projektioner. Race-condition-demo: två trådar uppdaterar samma konto.
0:20
Teori: optimistic vs pessimistic concurrency.
0:50
Teori: Polly-retry, exponential backoff, jitter.
1:20
Teori: idempotency-tabell + TransactionScope (exakt-en-gång).
2:05
Workshop: lägg in concurrency-handling. Race-test bevisar funktion.
3:45
Outbox-mönstret kort (förhandstitt mot saga i L9).
Talartips
Gör race-condition-demon live. Visa hur två POSTs samtidigt får "fel" resultat utan concurrency-skydd. Det skapar känslomässig motivation för lösningen.
Polly med jitter — visa varför pure exponential backoff är dåligt (thundering herd). Lägg in random ±25 %.
TransactionScope är förvirrande. Rita på whiteboard: två databasoperationer in i samma scope — antingen båda eller ingen.
Workshop
Visa misslyckad AppendToStream med fel expected-version → WrongExpectedVersionException.
Wrap:a den i egen ConcurrencyConflictException.
Lägg in Polly: 3 retries, exponential backoff (100 ms, 200, 400) + jitter.
Skapa dbo.IdempotencyKeys-tabell.
Lägg TransactionScope runt: skriv event + uppdatera read model + uppdatera checkpoint.
Race-test: 50 parallella POSTs till samma konto — verifiera att alla räknas och att inga events tappas.
Snabba Mät hur många retries som triggas. Logga distribution. Implementera outbox-tabell.
Stöd Para för pair-programming. Tillhandahåll race-test som färdig kod att köra.
FAQ
Varför inte pessimistic lock?
Skalbarhet. Pessimistic blockerar — optimistic försöker och rullar tillbaka vid konflikt. För majoriteten av användningar är konflikter sällsynta.
Hur många retries är "rätt"?
3 är vanligt. Mer än 5 betyder att kön (L8) borde användas istället för att eliminera konflikter.
Är TransactionScope inte föråldrat?
Nej, det är fullt supportat i .NET 10. Det är bara MSDTC (distribuerad) som man undviker — vi använder lokal lättviktstransaktion mot en databas.
Fallgrop Studenter glömmer att TransactionScope kräver TransactionScopeAsyncFlowOption.Enabled vid async-kod. Lägg in i alla exempel.
Hemuppgift Soloprojekt 1 lektion 07 (race-test + retry-mätning).
Förberedelse till L8 Studenten ska reflektera: "kan vi undvika konflikten istället för att hantera den?" — bro till command-kön.
← L6
L8 →