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);| Limit | Deklarácia | Kód zamietnutia | Systémový kontext |
|---|---|---|---|
| Maximálny počet | transition()->maxOccurrences(3) | max_occurrences_reached | platí |
| Cooldown | transition()->cooldown('24 hours') | cooldown_active | preskočí sa |
| Minimálny čas v stave | state()->minDwell('1 hour') | min_dwell_not_reached | preskočí sa |
| Zapečatenie | state()->sealedAfter('90 days') | sealed | platí |
| Zmrazenie | Lifecycles::for($m)->freeze() | frozen | platí |
| Termíny | notBefore() / notAfter() | not_yet_available / deadline_passed | platí |
| Rate limit | transition()->rateLimit(10, '1 hour') | rate_limited | preskočí sa |
| Kvóta | state()->quota(5, scope: 'user_id') | quota_exceeded | platí |
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 subjectKvó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 frozenZmrazený 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 kryptomienOdoslaní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.