Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/shastick/zio-prefetcher
When caching is not enough. Pre-fetch everything you need to RAM and refresh it on a regular basis.
https://github.com/shastick/zio-prefetcher
caching prefetching scala zio
Last synced: 17 days ago
JSON representation
When caching is not enough. Pre-fetch everything you need to RAM and refresh it on a regular basis.
- Host: GitHub
- URL: https://github.com/shastick/zio-prefetcher
- Owner: Shastick
- License: apache-2.0
- Created: 2020-08-18T11:31:38.000Z (about 4 years ago)
- Default Branch: main
- Last Pushed: 2022-05-27T16:52:31.000Z (over 2 years ago)
- Last Synced: 2024-10-09T12:31:43.502Z (28 days ago)
- Topics: caching, prefetching, scala, zio
- Language: Scala
- Homepage:
- Size: 60.5 KB
- Stars: 17
- Watchers: 3
- Forks: 2
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# `zio-prefetcher`
RAM is cheap. Caches can behave in unpredictable ways. Thus:
> Either things are in RAM or they don't exist.
## What's a Prefetcher?
A prefetcher is something that will do some work _in advance_ of when it is needed, while keeping the result around until it is eventually useful.Hence, the time it takes to access pre-fetched things is entirely predictable. Think of a prefetcher as a `Supplier[T]`
that returns a `T` immediately while regulary refreshing itself in the backgroundNote that it is _slightly_ different from a cache. Please refer to [this blog post](https://j3t.ch/tech/prefetching-pattern/) for some further context.
## How To Use
```scala
type PrefetchedVal = Map[UserId, UserSettings]
val supplier(): ZIO[PrefetchedVal, Throwable, PrefetchedVal] = ...
for {
prefetcher <- PrefetchingSupplier.withInitialValue(initialValue = Map(), supplier = supplier(), updateInterval = 1.second)
...
instantAccess <- prefetcher.currentValueRef.get
settings = instantAccess(someUserId)
...
} yield ...```
The artifact coordinates are:
```
libraryDependencies += "ch.j3t" %% "zio-prefetcher" % version
```[Check over here for all available versions](https://mvnrepository.com/artifact/ch.j3t/zio-prefetcher)
This library is built against `zio` version `1.0.7` and `zio-logging` version `0.5.8` but expects you to provide `zio` and `zio-logging` at runtime.
Additionally, if you intend to rely on the pre-fetchers that expose metrics, you'll need to provide `zio-metrics-dropwizard`.
## Example use cases
Assume a service with some users and their associated settings saved somewhere in a storage engine.
Occasionally, these settings may change, but it's OK if updates don't propagate immediately.In your code, you have some implementation of `UserId => Future[UserSettings]`. This is nice, but...
Your constraints may be such that looking up some settings in the backend takes too much time to your taste (_very_ picky users, crappy database, ...)
Assuming you have some spare RAM, you can set up a prefetcher such that you'll always have a `Map[UserId, UserSettings]`
sitting around, ready to be used. Now you can access all existing settings with a direct map lookup at any time.# Consideration
## When to use a pre-fetcher
A pre-fetcher can be useful in situations where you have some data (configuration or otherwise) that is either:
- entirely static
- rarely updated
- robust to staleness (ie, for which not immediately having the latest version is OK).
Combined with access costs that range from _annoying_ to _prohibitive_, eg:
- latencies to reach some other service
- complex queries that take a (long) while but yield small results
And assuming that everything you generally need fits in RAM...For cases that match all the above, it can be interesting to rely on pre-fetched data instead of looking things up
through an external service, be it with or without some caching involved.## What does this solve that a cache cannot?
Caches are great, no questions here.
The issue with a cache, in general, is that on a cache miss, the caller still needs to wait.
Having a cache that pre-loads all possible queries or arguments to a function or service, while pro-actively refreshing
the cached values if required, would solve for that problem.However, if you do so, you essentially end up with a _prefetcher_, not using the other cache features like eviction policies:
This pre-fetcher is intended for use in exactly such cases.## How it came to be
I've been using this _prefetching pattern_ in some projects, and am currently learning more about ZIO.
Making a pure ZIO prefetcher seemed like a nice little challenge.## Disclaimer
This is ~~some toy-code that will see some production use~~ actually being used in production but is,
nevertheless, written by a relative ZIO-Newbie: so use it at your own risks.