NovinkaZverejnili sme 50+ Laravel balíkov ako open source
Custom AI apps, agents and automation — Roundly ConsultingRoundly
Všetky balíky
Lifecycle for Laravel

Limity, kvóty a zmrazenie

Limity sú súčasťou definície — na stave, do ktorého sa vstupuje alebo z ktorého sa odchádza, alebo na prechode:

$lifecycle->state(ListingStatus::Active)
    ->quota(fn (Listing $listing): int => $listing->user->plan->max_active, scope: 'user_id')
    ->minDwell('1 hour')
    ->sealedAfter('90 days');

$lifecycle->transition('reopen')
    ->from(ListingStatus::Closed)->to(ListingStatus::Active)
    ->maxOccurrences(3)
    ->cooldown('24 hours')
    ->rateLimit(10, '1 hour', RateLimitScope::Actor);
LimitDeklaráciaKód zamietnutiaSystémový kontext
Maximálny počettransition()->maxOccurrences(3)max_occurrences_reachedplatí
Cooldowntransition()->cooldown('24 hours')cooldown_activepreskočí sa
Minimálny čas v stavestate()->minDwell('1 hour')min_dwell_not_reachedpreskočí sa
Zapečateniestate()->sealedAfter('90 days')sealedplatí
ZmrazenieLifecycles::for($m)->freeze()frozenplatí
TermínynotBefore() / notAfter()not_yet_available / deadline_passedplatí
Rate limittransition()->rateLimit(10, '1 hour')rate_limitedpreskočí sa
Kvótastate()->quota(5, scope: 'user_id')quota_exceededplatí

Maximálny počet a cooldowny sa počítajú z počítadiel záznamu stavu, nikdy z histórie — čistenie histórie limit nikdy nevynuluje a rollback obnoví počítadlo, ktoré vrátený riadok zmenil. Časové limity sa dosiahnu, keď teraz ≥ limit, s výnimkou notAfter(): samotný termín je ešte povolený.

Kvóty

$lifecycle->state(ListingStatus::Active)
    ->quota(5, scope: 'user_id')                                              // static
    ->quota(fn (Listing $l): int => $l->user->plan->max_active, scope: 'user_id', name: 'plan'); // per subject

Kvóty počítajú vlastnú tabuľku subjektu: riadky v cieľovom stave s rovnakými hodnotami scope (hodnota NULL tvorí vlastnú skupinu), bez samotného subjektu a soft-deleted riadkov a bez globálnych scopes — konzolový sweep teda napočíta to isté ako request tenanta. Overujú sa, keď prechod alebo rollback do stavu vstupuje; vytvorenie, priame zápisy, obnovenie soft-deleted subjektu a prechody do toho istého stavu sa nepočítajú a kvóta na počiatočnom stave je chybou definície. Kvóta 0 odmietne každého.

Súbežné vstupy sa serializujú cez zámkový riadok pre každú hodnotu scope, takže ani nával požiadaviek limit neprekročí — overené pri skutočnej súbežnej záťaži na PostgreSQL a MySQL. Zmena stĺpca scope pri modeli, ktorý už v stave s kvótou je (presun inzerátu od používateľa A k B bežným save()), sa znova neoveruje.

Prechod do stavu s kvótou, ktorý by zároveň zmenil niektorý z jej stĺpcov scope — neuloženou úpravou modelu alebo v handleri či hooku — vyhodí InvalidLifecycleUsageException::quotaScopeChanged a nič nezmení, pretože počet aj zámok platili pre uloženú skupinu. Stĺpec uložte samostatne, pred prechodom alebo po ňom. Rollback počíta kvótu v skupine, ktorú obnoví.

Rate limity

use RoundlyConsulting\Lifecycle\Enums\RateLimitScope;

$lifecycle->transition('reopen')
    ->rateLimit(10, '1 hour', RateLimitScope::Actor)
    ->rateLimit(100, '1 day', RateLimitScope::Subject);

Rate limity idú cez RateLimiter Laravelu (váš cache store). Kľúč sa skladá z rate_limits.prefix, morph typu subjektu, cyklu, prechodu, aktéra a kľúča subjektu, pričom každá časť je escapovaná: limit na aktéra sa počíta na model, cyklus a prechod a volanie bez aktéra sa počíta na subjekt — nikdy nie v jednom spoločnom koši pre všetkých volajúcich bez aktéra. Pokusy sa započítajú, len ak prejdú všetky ostatné kontroly, a nikdy sa nevracajú, ani keď transakcia neskôr zlyhá. check() sa len pozrie; systémový kontext rate limity preskakuje.

Kľúč sa spolu s prefixom cache store a príponou :timer limitera musí zmestiť do 250 znakov. Kľúč, ktorý by sa nezmestil, vyhodí InvalidLifecycleUsageException::rateLimitKeyTooLong namiesto zlyhania v cache store a lifecycle:validate ho pri uvedených modeloch nahlási — veľmi dlhým názvom tried modelov dajte alias v morph mape.

Zmrazenie

Lifecycles::for($listing)->by($moderator)->because('Under review')->freeze(until: now()->addDays(3));
Lifecycles::for($listing)->isFrozen();      // true
Lifecycles::for($listing)->frozenUntil();   // ?CarbonImmutable
Lifecycles::for($listing)->frozenReason();  // 'Under review'
Lifecycles::for($listing)->unfreeze();      // bool: whether it was frozen

Zmrazený cyklus odmieta prechody (frozen), pokiaľ prechod nemá ignoresFreeze(), a rollbacky, pokiaľ ho nemá každý vracaný prechod. Splatné plány počkajú na koniec zmrazenia bez spotrebovania pokusu. Dôvod zmrazenia dlhší ako history.reason_max_length vyhodí InvalidLifecycleUsageException. Zmrazenie platí pre jeden cyklus jedného subjektu. Neoveruje sa voči pravidlám definície a aktér sa zaznamená len pre audit — freeze() autorizujte vlastnými policies.

Zapečatenie

sealedAfter('90 days'): keď je subjekt v stave takto dlho, prechody z neho (bez ignoresSeal()) aj rollbacky z neho sa odmietnu — aj v systémovom kontexte. Stav s TTL a sealedAfter() potrebuje expiračný prechod s ignoresSeal().

Prejavte lásku k open source

Tento balík je zadarmo pod licenciou MIT. Ak vám šetrí čas, jednorazový príspevok alebo členstvo na Patreone nám pomôže ho ďalej udržiavať, testovať a dokumentovať.

Ďalšie spôsoby podpory vrátane kryptomien

Odoslaním daru súhlasíte s našimi podmienkami prijímania darov.

Chcete to zabudovať do svojho produktu?

Naše balíky integrujeme do zákazkových Laravel a AI riešení. Napíšte nám, na čom pracujete, a ozveme sa do 48 hodín.