Cache - Postgres¶
Store cache entries in PostgreSQL through R2DBC, including expiry metadata.
Select POSTGRES through the core cache configuration and provide the database connection and cache schema described below. This is a cache provider; it is separate from the PostgreSQL EDA outbox transport.
| Maven artifact | Packaging | Source project |
|---|---|---|
org.fireflyframework:fireflyframework-cache-postgres |
jar |
modules/cache-postgres |
Part of Domain and data.
In the onboarding service¶
A service that already operates PostgreSQL can use a separate cache table for repeat application reads. Cached values remain separate from the authoritative application records.
Add the component¶
Installation and version availability explains source builds and published releases.
<dependency>
<groupId>org.fireflyframework</groupId>
<artifactId>fireflyframework-cache-postgres</artifactId>
<version>26.10.20-SNAPSHOT</version>
</dependency>
Quick start¶
The Java examples in this section are API fragments for application code. Use the stated imports and supply the application-owned collaborators described alongside them.
- Add the dependencies. The cache core and this adapter:
<dependencies>
<dependency>
<groupId>org.fireflyframework</groupId>
<artifactId>fireflyframework-cache</artifactId>
</dependency>
<dependency>
<groupId>org.fireflyframework</groupId>
<artifactId>fireflyframework-cache-postgres</artifactId>
</dependency>
</dependencies>
- Enable the provider and point it at your database in
application.yml:
firefly:
cache:
default-cache-type: POSTGRES # select this adapter (or AUTO to let the core pick)
postgres:
enabled: true
host: localhost
port: 5432
database: appdb
username: app
password: secret
- Use the unified cache API. Obtain a
CacheAdapterfrom the coreFireflyCacheManager; it is now backed by PostgreSQL with no other code changes:
import org.fireflyframework.cache.core.CacheAdapter;
import org.fireflyframework.cache.manager.FireflyCacheManager;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;
@Service
public class ProductService {
private final CacheAdapter cache;
public ProductService(FireflyCacheManager cacheManager) {
this.cache = cacheManager.getCache("products"); // CacheType.POSTGRES when selected
}
public Mono<Product> findById(String id) {
return cache.<String, Product>get(id, Product.class)
.flatMap(opt -> opt.map(Mono::just).orElseGet(() ->
loadFromDatabase(id).flatMap(p -> cache.put(id, p).thenReturn(p))));
}
}
Because every adapter implements the same CacheAdapter SPI, switching between Caffeine, Redis,
Hazelcast, JCache and PostgreSQL is a configuration change (firefly.cache.default-cache-type) plus
the matching dependency. Application code stays the same.
Configuration and wiring¶
This module declares no @ConfigurationProperties class of its own. Use the constructor/port contracts above and the configuration of the host or related core module.
Property-based wiring conditions found in this module:
prefix = "firefly.cache.postgres", name = "enabled", havingValue = "true". PostgresCacheAutoConfiguration.java.
Public API and extension points¶
| Type | Contract and responsibility |
|---|---|
PostgresCacheAdapter |
PostgreSQL-backed reactive cache adapter implemented over R2DBC. |
PostgresProvider |
CacheProviderFactory implementation that contributes the PostgreSQL R2DBC cache provider. |
PostgresCacheConfig |
Configuration for the PostgreSQL R2DBC cache adapter. |
PostgresCacheAutoConfiguration |
Auto-configuration for the PostgreSQL R2DBC cache provider. |
PostgresCacheHelper |
Self-contained factory helper that builds a PostgresCacheAdapter. |
Related components¶
| Related component | Why it belongs nearby |
|---|---|
| Common Cache Library | Use a common cache API with a local Caffeine default and pluggable distributed providers. |
Build and test¶
Use Java 25. From the repository root, build this component with its required dependencies:
git clone https://github.com/fireflyframework/fireflyframework-jafly.git
cd fireflyframework-jafly
./mvnw -pl :fireflyframework-cache-postgres -am verify
./mvnw -pl :fireflyframework-cache-postgres -am install
verify runs the selected projects' tests. install makes the current build available in your local Maven repository.
Representative test sources:
Some tests use Testcontainers. A working Docker-compatible container runtime is required for those fixtures; inspect their annotations and the build output to distinguish executed tests from environment-dependent skips.
Test fixture¶
The evictRemovesEntry test demonstrates one concrete behavior. Excerpt from PostgresCacheAdapterIntegrationTest.java. The test class supplies its fixtures and imports.
@Test
void evictRemovesEntry() {
adapter.put("toEvict", "value").block(Duration.ofSeconds(5));
StepVerifier.create(adapter.evict("toEvict"))
.expectNext(true)
.verifyComplete();
StepVerifier.create(adapter.exists("toEvict"))
.expectNext(false)
.verifyComplete();
// Evicting an absent key returns false.
StepVerifier.create(adapter.evict("toEvict"))
.expectNext(false)
.verifyComplete();
}
Detailed reference¶
Configuration¶
All adapter-specific properties live under the firefly.cache.postgres prefix and are bound by the
core CacheProperties.PostgresConfig. The active provider is chosen by the core-owned
firefly.cache.default-cache-type key.
firefly:
cache:
default-cache-type: POSTGRES # core: choose the active provider (default: CAFFEINE)
postgres:
enabled: true # default: false
host: localhost # default: localhost
port: 5432 # default: 5432
database: appdb # default: none
username: app # default: none
password: secret # default: none
schema: public # default: public
cache-table: firefly_cache_entries # default: firefly_cache_entries
cache-name: default # default: default
key-prefix: "" # default: empty
default-ttl: PT30M # default: 30 minutes
auto-create-schema: true # default: true
max-pool-size: 10 # default: 10
min-pool-size: 1 # default: 1
properties: {} # extra R2DBC driver options
| Property | Type | Default | Description |
|---|---|---|---|
firefly.cache.default-cache-type |
CacheType |
CAFFEINE |
Core property selecting the active provider. Set to POSTGRES (or AUTO) to use this adapter. |
firefly.cache.postgres.enabled |
boolean |
false |
Enables the PostgreSQL cache provider and its auto-configuration. |
firefly.cache.postgres.host |
String |
localhost |
PostgreSQL host. |
firefly.cache.postgres.port |
int |
5432 |
PostgreSQL port. |
firefly.cache.postgres.database |
String |
. | Database name. |
firefly.cache.postgres.username |
String |
. | Database username. |
firefly.cache.postgres.password |
String |
. | Database password. |
firefly.cache.postgres.schema |
String |
public |
Schema that holds the cache table. |
firefly.cache.postgres.cache-table |
String |
firefly_cache_entries |
Cache table name. |
firefly.cache.postgres.cache-name |
String |
default |
Default logical cache name. |
firefly.cache.postgres.key-prefix |
String |
"" |
Prefix applied to namespaced keys. |
firefly.cache.postgres.default-ttl |
Duration |
PT30M |
Default entry TTL; zero/negative means no expiration. |
firefly.cache.postgres.auto-create-schema |
boolean |
true |
Create the cache table and expiry index on startup. |
firefly.cache.postgres.max-pool-size |
int |
10 |
Maximum R2DBC pool connections. |
firefly.cache.postgres.min-pool-size |
int |
1 |
Initial/minimum R2DBC pool connections. |
firefly.cache.postgres.properties |
Map |
{} |
Extra options passed to the PostgreSQL R2DBC driver. |
Connection settings come only from
firefly.cache.postgres.*, never fromspring.r2dbc.*: the cache uses a dedicated, pooledConnectionFactorybean (fireflyCachePostgresConnectionFactory) independent of your application datasource.
Storage schema¶
When auto-create-schema is true, the adapter provisions (idempotently) the following table and a
partial index supporting expiry scans:
CREATE TABLE IF NOT EXISTS "public"."firefly_cache_entries" (
cache_name VARCHAR(255) NOT NULL,
cache_key VARCHAR(1024) NOT NULL,
value BYTEA NOT NULL,
expires_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
PRIMARY KEY (cache_name, cache_key)
);
CREATE INDEX IF NOT EXISTS firefly_cache_entries_expires_idx
ON "public"."firefly_cache_entries" (expires_at) WHERE expires_at IS NOT NULL;
If you disable auto-create-schema, create this table and index manually before first use.
How It Works¶
PostgresCacheAutoConfiguration(org.fireflyframework.cache.config). Spring Boot@AutoConfigurationregistered inMETA-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. Activates when the R2DBC SPI is on the classpath andfirefly.cache.postgres.enabled=true. Builds the pooledfireflyCachePostgresConnectionFactorybean and, when enabled, provisions the schema.PostgresProvider(org.fireflyframework.cache.spi.providers). theCacheProviderFactorySPI implementation, registered forServiceLoaderinMETA-INF/services/org.fireflyframework.cache.spi.CacheProviderFactory. ReportsCacheType.POSTGRESwith priority 15 and is available when the connection factory is present and the provider is enabled.PostgresCacheHelper(org.fireflyframework.cache.factory). the factory helper the cache core references reflectively to build adapters; its fully-qualified name is load-bearing and must not be renamed or moved.PostgresCacheAdapter(org.fireflyframework.cache.adapter.postgres). theCacheAdapterimplementation. Stores entries in the relational table via the R2DBCConnectionFactory, serializes values withJsonCacheSerializer, namespaces keys per cache, enforces TTL, and reportsCacheStats/CacheHealth.PostgresCacheConfig(org.fireflyframework.cache.adapter.postgres). immutable per-adapter config (cache name, key prefix, default TTL, schema, table).
Continue the application¶
Use the Cache guide for the next part of this integration. The runnable submission/query service is in Getting started.