AI 资讯
Cache Invalidation — Stale Data
Stale data và cache stampede: vì sao TTL một mình không đủ và vì sao origin sập khi key hết hạn Stale data là dữ liệu trong cache đã lỗi thời so với source of truth. Nó xuất hiện vì cache và origin là hai bản sao, và bất kỳ cơ chế đồng bộ nào — TTL, event-based invalidation, versioning — đều có cửa sổ giữa lúc origin đổi và lúc cache biết chuyện. Cái giá phải trả trong production không chỉ là "user nhìn thấy giá cũ vài giây". Khi một key hot vừa hết hạn, hàng nghìn request cùng miss, cùng đâm xuống DB để tính lại — đó là cache stampede (dogpile, thundering herd), và nó đủ sức đưa origin xuống trong vài chục giây. Cơ chế hoạt động Có bốn cơ chế invalidation dùng thật: TTL (time-to-live). Mỗi entry gắn một hạn dùng. Hết hạn coi như miss, đọc lại từ origin. Đơn giản, không cần coordination giữa writer và cache. Nhược điểm: staleness bounded bởi TTL, và tất cả replica của cùng một key hết hạn cùng lúc. Event-based invalidation. Khi origin thay đổi, phát một event (thường qua pub/sub, CDC như Debezium, hoặc gọi trực tiếp DEL) để cache xoá hoặc cập nhật entry. Fresh gần như realtime, nhưng đòi hỏi coupling giữa write path và cache — writer phải biết mọi key phái sinh từ dữ liệu vừa đổi. Versioning (cache key có version). Key gắn version của dữ liệu, ví dụ user:123:v42 . Đổi dữ liệu thì tăng version, key cũ tự nhiên bị bỏ qua, không cần xoá gì. Kỹ thuật này còn được gọi là generational caching; Rails cache dùng cách tương tự với cache_key_with_version . Single-flight (request coalescing). Không phải invalidation, mà là cách xử lý miss: khi N request cùng miss cùng một key, chỉ một trong số đó được phép gọi origin, các request còn lại đợi kết quả của nó. Go có golang.org/x/sync/singleflight implement sẵn pattern này; Facebook memcache dùng "leases" (paper của Nishtala et al., NSDI 2013) cho cùng ý tưởng ở scale phân tán. Kết hợp điển hình: TTL để bounded staleness, single-flight để chặn stampede khi key hết hạn, event-based invalidation để cắt TTL sớm khi có write. Ví dụ si
AI 资讯
How Do You Log Someone Out of a Stateless System? JWT Invalidation on Logout
JWTs are one of those technologies that feel wonderful right up until you hit your first "log me out" requirement. Then you discover the awkward truth: the very property that makes JWTs attractive — statelessness — is also what makes logout hard. This post walks through what JWTs actually are, why "invalidating" one is a design problem rather than a one-liner, and the practical methods available to revoke an access token on logout, along with the bottleneck each one introduces. A quick refresher on JWTs A JSON Web Token (JWT) is a signed, self-contained token. It carries a JSON payload of claims — who the user is, when the token was issued, when it expires, and often a unique token id ( jti ) — and a cryptographic signature over that payload. Because the token is signed with a secret (or a private key), any server holding the corresponding key can verify it is authentic and untampered without calling a database . That last part is the entire point. When a request arrives with a JWT, the server checks the signature and the expiry, reads the claims, and proceeds. No lookup, no shared session store, no round trip. This is what people mean when they call JWT auth stateless : the server keeps no per-user session record. The token itself is the session, and it's valid until it expires. Access tokens and refresh tokens In practice you rarely use a single token. The common pattern splits responsibility across two: The access token is the short-lived workhorse. It's sent on every API request and typically expires in minutes (5–15 is common). Because it's checked statelessly on every call, you want its lifetime short — if it leaks, the damage window is small. The refresh token is long-lived (days or weeks) and does one job: obtain new access tokens when the current one expires. It is not sent on every request — only to a dedicated token endpoint. This lets the access token stay short and stateless while the user avoids logging in every ten minutes. The refresh token is easy —
AI 资讯
Laravel Precognition: Live Validation That Reuses Your Backend Rules
Book: Decoupled PHP — Clean and Hexagonal Architecture for Applications That Outlive the Framework Also by me: Thinking in Go (2-book series) — Complete Guide to Go Programming + Hexagonal Architecture in Go My project: Hermes IDE | GitHub — an IDE for developers who ship with Claude Code and other AI coding tools Me: xgabriel.com | GitHub You have two copies of the same rules. One lives in a StoreUserRequest on the server. The other lives in a Zod schema, or a Yup object, or a pile of required attributes, on the front end. They started identical. Then someone bumped the password minimum from 8 to 12 on the backend and forgot the client. Now the form says the password is fine, the user clicks submit, and a 422 bounces back with an error the UI never predicted. That drift is the whole reason live client-side validation is annoying to maintain. You are keeping two rulesets in sync by hand, and the sync breaks quietly. Laravel Precognition removes the second copy. The front end asks the server "would this pass?" before the user submits, and the server answers using the exact same validation rules the real request will run. What a precognitive request actually is A precognitive request is a normal HTTP request to your real endpoint, tagged with a Precognition: true header. Laravel sees the header, runs the route's middleware and validation, and then stops before your controller does any real work. It never writes a row. It never sends an email. It runs the rules and returns the verdict. Success comes back as 204 No Content with a Precognition-Success: true header. Failure comes back as a normal 422 with the same JSON error bag your form submit would produce. Same rules, same messages, same field names. There is no second schema to drift. The lifecycle is worth holding in your head: Front end sends the form state to the real URL with Precognition: true . Middleware runs. FormRequest validation runs. Laravel short-circuits: your controller body never executes. Response is