Table of Contents

Class DistributedLock

Namespace
UsluzionicaServer.Infrastructure.Redis
Assembly
UsluzionicaServer.dll

Distribuirani lock — obezbeđuje da posao izvrši TAČNO JEDNA instanca.

Zašto je potreban: BackgroundService se pokreće u svakom procesu. Sa dve instance API-ja, BoostExpiryService bi u istom trenutku na obe krenuo da oduzima BoostScore istim oglasima — pa bi svaki oglas bio umanjen dvaput. MessageCleanupService bi dvaput brisao (bezopasno) ali bi i dvaput logovao i dvaput opteretio bazu.

Mehanizam je Redis SET key value NX PX ttl: NX → upiši SAMO ako ključ ne postoji (atomično, na strani Redis-a) PX → automatski istekni posle ttl milisekundi

TTL je ono što ovo čini bezbednim. Ako instanca koja drži lock pukne ili joj neko povuče struju, lock se sam oslobodi posle TTL-a. Bez TTL-a bi jedan pad zauvek zaustavio taj posao na celom klasteru.

TTL zato mora biti DUŽI od najdužeg očekivanog trajanja posla. Ako posao traje duže, drugi ga preuzme dok prvi još radi — i vraćamo se na problem koji smo rešavali.

public sealed class DistributedLock
Inheritance
DistributedLock
Inherited Members

Constructors

DistributedLock(RedisConnection, ILogger<DistributedLock>)

Distribuirani lock — obezbeđuje da posao izvrši TAČNO JEDNA instanca.

Zašto je potreban: BackgroundService se pokreće u svakom procesu. Sa dve instance API-ja, BoostExpiryService bi u istom trenutku na obe krenuo da oduzima BoostScore istim oglasima — pa bi svaki oglas bio umanjen dvaput. MessageCleanupService bi dvaput brisao (bezopasno) ali bi i dvaput logovao i dvaput opteretio bazu.

Mehanizam je Redis SET key value NX PX ttl: NX → upiši SAMO ako ključ ne postoji (atomično, na strani Redis-a) PX → automatski istekni posle ttl milisekundi

TTL je ono što ovo čini bezbednim. Ako instanca koja drži lock pukne ili joj neko povuče struju, lock se sam oslobodi posle TTL-a. Bez TTL-a bi jedan pad zauvek zaustavio taj posao na celom klasteru.

TTL zato mora biti DUŽI od najdužeg očekivanog trajanja posla. Ako posao traje duže, drugi ga preuzme dok prvi još radi — i vraćamo se na problem koji smo rešavali.

Methods

TryAcquireAsync(string, TimeSpan)

Pokušava da zauzme lock. Vraća objekat koji ga oslobađa pri dispose-u, ili null ako ga druga instanca već drži.

KAD REDIS NIJE DOSTUPAN vraća lock koji ništa ne radi — dakle posao se IZVRŠAVA. To je namerno: sa jednom instancom (razvoj, testovi, mali deployment) nema šta da se štiti, a odbijanje posla bi značilo da se boostovi nikad ne gase ako Redis ispadne.