{"id":16120456,"url":"https://github.com/sksamuel/aedile","last_synced_at":"2025-04-04T13:09:39.286Z","repository":{"id":59656292,"uuid":"538294188","full_name":"sksamuel/aedile","owner":"sksamuel","description":"Kotlin Wrapper for Caffeine","archived":false,"fork":false,"pushed_at":"2025-02-03T03:41:33.000Z","size":259,"stargazers_count":187,"open_issues_count":1,"forks_count":15,"subscribers_count":6,"default_branch":"main","last_synced_at":"2025-03-29T13:47:51.214Z","etag":null,"topics":["cache","caffeine","coroutines","java","kotlin"],"latest_commit_sha":null,"homepage":"","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sksamuel.png","metadata":{"files":{"readme":"README.md","changelog":"changelog.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-09-19T01:42:29.000Z","updated_at":"2025-03-27T20:32:19.000Z","dependencies_parsed_at":"2023-01-31T17:31:25.768Z","dependency_job_id":"785cfe0d-1663-4112-b1f0-65d88b7f745b","html_url":"https://github.com/sksamuel/aedile","commit_stats":null,"previous_names":[],"tags_count":18,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sksamuel%2Faedile","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sksamuel%2Faedile/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sksamuel%2Faedile/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sksamuel%2Faedile/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sksamuel","download_url":"https://codeload.github.com/sksamuel/aedile/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247182335,"owners_count":20897379,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cache","caffeine","coroutines","java","kotlin"],"created_at":"2024-10-09T20:58:26.429Z","updated_at":"2025-04-04T13:09:39.262Z","avatar_url":"https://github.com/sksamuel.png","language":"Kotlin","funding_links":[],"categories":["java"],"sub_categories":[],"readme":"# Aedile\n\n![main](https://github.com/sksamuel/aedile/workflows/main/badge.svg)\n[\u003cimg src=\"https://img.shields.io/maven-central/v/com.sksamuel.aedile/aedile-core.svg?label=latest%20release\"/\u003e](https://central.sonatype.com/search?q=aedile)\n[\u003cimg src=\"https://img.shields.io/nexus/s/https/s01.oss.sonatype.org/com.sksamuel.aedile/aedile-core.svg?label=latest%20snapshot\u0026style=plastic\"/\u003e](https://s01.oss.sonatype.org/content/repositories/snapshots/com/sksamuel/aedile/)\n\nAedile is a simple Kotlin wrapper for [Caffeine](https://github.com/ben-manes/caffeine) which prefers coroutines rather\nthan Java futures.\n\nSee [changelog](changelog.md)\n\n## Features\n\n* **Suspendable functions:** Rather than use Java's `CompletableFuture`s, all operations on Aedile are suspendable and\n  executed in their own coroutines.\n* **Backed by Caffeine:** This is not a new cache implementation with its own bugs and quirks, but a simple wrapper\n  around Caffeine which has been used on the JVM for years.\n* **Kotlin durations:** Specify expiration and refresh times in `kotlin.time.Duration` rather than Java durations.\n* **Kotlin functions:** Wherever a function is required - eg eviction listener - Aedile supports Kotlin functions\n  rather than Java's Function interface.\n\n## Usage\n\nAdd Aedile to your build:\n\n```groovy\nimplementation 'com.sksamuel.aedile:aedile-core:\u003cversion\u003e'\n```\n\nNext, in your code, create a cache configuration using the standard Caffeine builder. Then, instead of using the\n`buildAsync` methods that Caffeine provides, use the `asCache` or `asLoadingCache` methods that Aedile provides.\n\n```kotlin\nval cache = Caffeine.newBuilder().asCache\u003cString, String\u003e()\n```\n\nWith this cache we can request values if present, or supply a suspendable function to compute them.\n\n```kotlin\nval value1 = cache.getIfPresent(\"foo\") // value or null\n\nval value2 = cache.get(\"foo\") {\n   delay(100) // look ma, we support suspendable functions!\n   \"value\"\n}\n```\n\nThe `asLoadingCache` method supports a generic compute function which is used if no specific compute function is\nprovided.\n\n```kotlin\nval cache = Caffeine.newBuilder().asLoadingCache\u003cString, String\u003e() {\n   delay(1) // look ma, we support suspendable functions!\n   \"value\"\n}\n\ncache.get(\"foo\") // uses default compute, will return \"value\"\ncache.get(\"bar\") { \"other\" } // uses specific compute function to return \"other\"\n```\n\n## Configuration\n\nWhen creating the cache, Aedile wraps the standard Caffeine configuration options, adding extension functions to make\nit easier to use Kotlin types - such as `kotlin.time.Duration` rather than Java's `Duration`.\n\nFor example:\n\n```kotlin\nval cache = Caffeine\n   .newBuilder()\n   .expireAfterWrite(1.hours) // supports kotlin.time.Duration\n   .maximumSize(100) // standard Caffeine option\n   .asCache\u003cString, String\u003e()\n```\n\n## Evictions\n\nCaffeine provides different approaches to eviction:\n\n* expireAfterAccess(duration): Expire entries after the specified duration has passed since the entry was last accessed\n  by a read or write. This could be desirable if the cached data is bound to a session and expires due to inactivity.\n\n* expireAfterWrite(duration): Expire entries after the specified duration has passed since the entry was created, or the\n  most recent replacement of the value. This could be desirable if cached data grows stale after a certain amount of\n  time.\n\n* expireAfter(expiry): Pass an implementation of `Expiry` which has methods for specifying that expiry should occur\n  either after a duration from insert, a duration from last refresh, or a duration from last read.\n\n* invalidate / invalidateAll: Programatically remove entries based on their key(s) or remove all entries. In the case of\n  a loading cache, any currently loading values may not be removed.\n\nYou can specify a suspendable function to listen to evictions using the `withEvictionListener` method.\n\n```kotlin\nval cache = Caffeine\n   .newBuilder()\n   .expireAfterWrite(1.hours) // supports kotlin.time.Duration\n   .maximumSize(100) // standard Caffeine option\n   .asCache\u003cString, String\u003e()\n   .withEvictionListener { key, value, cause -\u003e\n      when (cause) {\n         RemovalCause.SIZE -\u003e println(\"Removed due to size constraints\")\n         else -\u003e delay(100) // suspendable for no real reason, but just to show you can!!\n      }\n   }.asCache\u003cString, String\u003e()\n```\n\n## Removals\n\nSimilar to evictions, you can specify a suspendable function to listen to removals using the `withRemovalListener`\nmethod.\n\n```kotlin\nval cache = Caffeine\n   .newBuilder()\n   .asCache\u003cString, String\u003e()\n   .withRemovalListener { key, value, cause -\u003e\n      ...\n   }.asCache\u003cString, String\u003e()\n```\n\n## Coroutine Context\n\nAedile will use the context from the calling function for executing the compute functions. You can\nspecify your own context by just switching the context like with any suspendable call.\n\n```kotlin\nval cache = Caffeine.newBuilder().asCache\u003cString, String\u003e()\nval value = cache.get(\"foo\") {\n   withContext(Dispatchers.IO) {\n      // blocking database call\n   }\n}\n```\n\n## Metrics\n\n[Micrometer](https://micrometer.io) provides integration which wraps the Caffeine cache classes.\nTo use this, call `.underlying()` to get access to the wrapped Caffeine instance.\n\nFor example:\n\n```kotlin\nCaffeineCacheMetrics(cache.underlying().synchronous(), \"my-cache-name\", tags).bindTo(registry)\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsksamuel%2Faedile","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsksamuel%2Faedile","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsksamuel%2Faedile/lists"}