whitfin / cachex

A powerful caching library for Elixir with support for transactions, fallbacks and expirations
https://hexdocs.pm/cachex/
MIT License
1.6k stars 103 forks source link

Improve performance and lower overhead in Janitor services #375

Closed whitfin closed 1 month ago

whitfin commented 1 month ago

This fixes #367.

This PR will introduce the notion of Cachex.Provision to cache services, so they can also be provisioned just like hooks and warmers. As the Janitor uses :cache, this removes a table lookup on every call of the Janitor.

Also included is a change to Cachex.Router to allow actions which don't support distribution (i.e. Cachex.stream/3) to be called on the local node if local: true. This means we can go via Cachex.stream/3 rather than Cachex.Action.Stream.execute/3 when re-using it internally.

Lastly the flow of the Janitor purge itself has changed. A Janitor is now flagged as "inactive" during initialization. An inactive Janitor will only do a quick sample to determine if there are any records in the cache with expiration set. If there aren't, it'll just short-circuit and repeat this process until there are. To clarify "with expiration" does not mean "expired", just that the field is not nil in a single record.

Once a record with expiration is detected, it'll flag the Janitor as "active" and going forward the purge cycles will run as previously (including immediately). The previous sample will no longer run, so there's no overhead here compared to behaviour before this PR.

Although this sounds more complicated, it skips out on the call to Cachex.purge/2 which uses Locksmith.transaction/3 under the hood and places a lock on the entire table. If you're not using expirations, this overhead will no longer affect you until you are, which is much better!