Skip to content

Commit

Permalink
Improve hibernate example and add resilience example using failsafe
Browse files Browse the repository at this point in the history
  • Loading branch information
ben-manes committed Aug 5, 2023
1 parent c2befe9 commit 2c7b878
Show file tree
Hide file tree
Showing 25 changed files with 717 additions and 35 deletions.
4 changes: 4 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ updates:
directory: examples/hibernate
schedule:
interval: daily
- package-ecosystem: gradle
directory: examples/resilience-failsafe
schedule:
interval: daily
- package-ecosystem: gradle
directory: examples/graal-native
schedule:
Expand Down
5 changes: 4 additions & 1 deletion .github/workflows/examples.yml
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,12 @@ jobs:
- name: Coalescing Bulkloader
working-directory: examples/coalescing-bulkloader
run: ./mvnw test
- name: Hibernate JCache
- name: Hibernate (jcache)
working-directory: examples/hibernate
run: ./gradlew build
- name: Resilience (failsafe)
working-directory: examples/resilience-failsafe
run: ./gradlew build
- name: Prepare for Graal Native Image
uses: ./.github/actions/run-gradle
with:
Expand Down
6 changes: 4 additions & 2 deletions examples/graal-native/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@ application {
mainClass = "com.github.benmanes.caffeine.examples.graalnative.Application"
}

tasks.test {
useJUnitPlatform()
testing.suites {
val test by getting(JvmTestSuite::class) {
useJUnitJupiter()
}
}

graalvmNative {
Expand Down
4 changes: 4 additions & 0 deletions examples/graal-native/settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ pluginManagement {
gradlePluginPortal()
}
}
plugins {
id("org.gradle.toolchains.foojay-resolver-convention") version "0.6.0"
}

dependencyResolutionManagement {
repositories {
mavenCentral()
Expand Down
12 changes: 10 additions & 2 deletions examples/hibernate/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
The [Hibernate ORM] can be configured to use a [second-level cache] to reduce the number of accesses
[Hibernate] can be configured to use a [second-level cache] to reduce the number of accesses
to the database by caching data in memory to be shared between sessions.

In [hibernate.conf](src/main/resources/hibernate.properties) specify the JCache provider and enable
Expand Down Expand Up @@ -29,6 +29,14 @@ caffeine.jcache {
}
```

Enable caching on the entity.

```java
@Entity
@Cache(usage = READ_WRITE)
public class User { ... }
```

Hibernate will then manage the cache to transparently avoid database calls.

```java
Expand All @@ -41,5 +49,5 @@ sessionFactory.fromSession(session -> session.get(User.class, id));
assertThat(sessionFactory.getStatistics().getSecondLevelCacheHitCount()).isEqualTo(1);
```

[Hibernate ORM]: https://hibernate.org/orm/
[Hibernate]: https://hibernate.org/orm/
[second-level cache]: https://docs.jboss.org/hibernate/orm/6.3/introduction/html_single/Hibernate_Introduction.html#second-level-cache-configuration
8 changes: 5 additions & 3 deletions examples/hibernate/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,18 @@ plugins {

dependencies {
implementation(libs.bundles.hibernate)
implementation(libs.bundles.log4j2)
implementation(libs.caffeine)
implementation(libs.slf4j)
runtimeOnly(libs.h2)

testImplementation(libs.junit)
testImplementation(libs.truth)
}

tasks.test {
useJUnitPlatform()
testing.suites {
val test by getting(JvmTestSuite::class) {
useJUnitJupiter()
}
}

java.toolchain.languageVersion = JavaLanguageVersion.of(
Expand Down
5 changes: 4 additions & 1 deletion examples/hibernate/gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ caffeine = "3.1.7"
h2 = "2.2.220"
hibernate = "6.3.0.CR1"
junit = "5.10.0"
log4j2 = "2.20.0"
slf4j = "2.0.7"
truth = "1.1.5"
versions = "0.47.0"
Expand All @@ -14,11 +15,13 @@ hibernate-core = { module = "org.hibernate.orm:hibernate-core", version.ref = "h
hibernate-jcache = { module = "org.hibernate.orm:hibernate-jcache", version.ref = "hibernate" }
hibernate-hikaricp = { module = "org.hibernate.orm:hibernate-hikaricp", version.ref = "hibernate" }
junit = { module = "org.junit.jupiter:junit-jupiter", version.ref = "junit" }
slf4j = { module = "org.slf4j:slf4j-jdk14", version.ref = "slf4j" }
log4j2-core = { module = "org.apache.logging.log4j:log4j-core", version.ref = "log4j2" }
log4j2-slf4j = { module = "org.apache.logging.log4j:log4j-slf4j-impl", version.ref = "log4j2" }
truth = { module = "com.google.truth:truth", version.ref = "truth" }

[bundles]
hibernate = ["hibernate-core", "hibernate-jcache", "hibernate-hikaricp"]
log4j2 = ["log4j2-core", "log4j2-slf4j"]

[plugins]
versions = { id = "com.github.ben-manes.versions", version.ref = "versions" }
4 changes: 4 additions & 0 deletions examples/hibernate/settings.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
plugins {
id("org.gradle.toolchains.foojay-resolver-convention") version "0.6.0"
}

dependencyResolutionManagement {
repositories {
mavenCentral()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,10 @@
*/
package com.github.benmanes.caffeine.examples.hibernate;

import static jakarta.persistence.AccessType.FIELD;
import static org.hibernate.annotations.CacheConcurrencyStrategy.READ_WRITE;

import org.hibernate.annotations.Cache;

import jakarta.persistence.Access;
import jakarta.persistence.Cacheable;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
Expand All @@ -31,8 +28,6 @@
* @author [email protected] (Ben Manes)
*/
@Entity
@Cacheable
@Access(FIELD)
@Cache(usage = READ_WRITE)
public class Project {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,10 @@
*/
package com.github.benmanes.caffeine.examples.hibernate;

import static jakarta.persistence.AccessType.FIELD;
import static org.hibernate.annotations.CacheConcurrencyStrategy.READ_WRITE;

import org.hibernate.annotations.Cache;

import jakarta.persistence.Access;
import jakarta.persistence.Cacheable;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
Expand All @@ -30,8 +27,6 @@
* @author [email protected] (Ben Manes)
*/
@Entity
@Cacheable
@Access(FIELD)
@Cache(usage = READ_WRITE)
public class Skill {
@Id
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,13 @@
*/
package com.github.benmanes.caffeine.examples.hibernate;

import static jakarta.persistence.AccessType.FIELD;
import static org.hibernate.annotations.CacheConcurrencyStrategy.READ_WRITE;

import java.util.ArrayList;
import java.util.List;

import org.hibernate.annotations.Cache;

import jakarta.persistence.Access;
import jakarta.persistence.Cacheable;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
Expand All @@ -35,8 +32,6 @@
* @author [email protected] (Ben Manes)
*/
@Entity
@Cacheable
@Access(FIELD)
@Cache(usage = READ_WRITE)
public class User {
@Id
Expand Down
7 changes: 2 additions & 5 deletions examples/hibernate/src/main/resources/hibernate.properties
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
hibernate.dialect=org.hibernate.dialect.H2Dialect

hibernate.connection.provider_class=org.hibernate.hikaricp.internal.HikariCPConnectionProvider
hibernate.connection.driver_class=org.h2.Driver
hibernate.connection.url=jdbc:h2:mem:test
hibernate.connection.username=sa

hibernate.show_sql=false
hibernate.format_sql=true
hibernate.format_sql=false
hibernate.highlight_sql=true
hibernate.globally_quoted_identifiers=true

hibernate.hbm2ddl.auto=create-drop
Expand Down
14 changes: 14 additions & 0 deletions examples/hibernate/src/main/resources/log4j2.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
rootLogger.level = info
rootLogger.appenderRefs = console
rootLogger.appenderRef.console.ref = console

logger.hibernate.name = org.hibernate
logger.hibernate.level = warn

logger.hikaricp.name = com.zaxxer.hikari
logger.hikaricp.level = warn

appender.console.name = console
appender.console.type = Console
appender.console.layout.type = PatternLayout
appender.console.layout.pattern = %highlight{[%p]} %c %m%n
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,6 @@

import static com.github.benmanes.caffeine.examples.hibernate.HibernateSubject.assertThat;

import java.util.logging.Level;
import java.util.logging.Logger;

import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
Expand All @@ -36,7 +33,6 @@ public final class HibernateCacheTest {

@BeforeEach
public void beforeEach() {
Logger.getLogger("").setLevel(Level.WARNING);
sessionFactory = new Configuration().addAnnotatedClass(User.class)
.addAnnotatedClass(Skill.class).addAnnotatedClass(Project.class)
.buildSessionFactory(new StandardServiceRegistryBuilder().build());
Expand Down
57 changes: 57 additions & 0 deletions examples/resilience-failsafe/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
[Failsafe's][failsafe] retry, timeout, and fallback strategies can be used to make the cache
operations resiliant to intermittent failures.

### Retry
A [retry policy][retry] will retry failed executions a certain number of times, with an optional
delay between attempts.

```java
var retryPolicy = RetryPolicy.builder()
.withDelay(Duration.ofSeconds(1))
.withMaxAttempts(3)
.build();
var failsafe = Failsafe.with(retryPolicy);

// Retry outside of the cache loader for synchronous calls
Cache<K, V> cache = Caffeine.newBuilder().build();
failsafe.get(() -> cache.get(key, key -> /* intermittent failures */ ));

// Optionally, retry inside the cache load for asynchronous calls
AsyncCache<K, V> asyncCache = Caffeine.newBuilder().buildAsync();
asyncCache.get(key, (key, executor) -> failsafe.getAsync(() -> /* intermittent failure */));
```

### Timeout
A [timeout policy][timeout] will cancel the execution if it takes too long to complete.

```java
var retryPolicy = RetryPolicy.builder()
.withDelay(Duration.ofSeconds(1))
.withMaxAttempts(3)
.build();
var timeout = Timeout.builder(Duration.ofSeconds(1)).withInterrupt().build();
var failsafe = Failsafe.with(timeout, retryPolicy);

Cache<K, V> cache = Caffeine.newBuilder().build();
failsafe.get(() -> cache.get(key, key -> /* timeout */ ));
```

### Fallback
A [fallback policy][fallback] will provide an alternative result for a failed execution.

```java
var retryPolicy = RetryPolicy.builder()
.withDelay(Duration.ofSeconds(1))
.withMaxAttempts(3)
.build();
var fallback = Fallback.of(/* fallback */);
var failsafe = Failsafe.with(fallback, retryPolicy);

Cache<K, V> cache = Caffeine.newBuilder().build();
failsafe.get(() -> cache.get(key, key -> /* failure */ ));
```

[failsafe]: https://failsafe.dev
[retry]: https://failsafe.dev/retry
[timeout]: https://failsafe.dev/timeout
[fallback]: https://failsafe.dev/fallback
27 changes: 27 additions & 0 deletions examples/resilience-failsafe/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
plugins {
`java-library`
alias(libs.plugins.versions)
}

dependencies {
implementation(libs.caffeine)
implementation(libs.failsafe)

testImplementation(libs.junit)
testImplementation(libs.truth)
}

testing.suites {
val test by getting(JvmTestSuite::class) {
useJUnitJupiter()
}
}

java.toolchain.languageVersion = JavaLanguageVersion.of(
System.getenv("JAVA_VERSION")?.toIntOrNull() ?: 11)

tasks.withType<JavaCompile>().configureEach {
javaCompiler = javaToolchains.compilerFor {
languageVersion = java.toolchain.languageVersion
}
}
15 changes: 15 additions & 0 deletions examples/resilience-failsafe/gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[versions]
caffeine = "3.1.7"
failsafe = "3.3.2"
junit = "5.10.0"
truth = "1.1.5"
versions = "0.47.0"

[libraries]
caffeine = { module = "com.github.ben-manes.caffeine:caffeine", version.ref = "caffeine" }
failsafe = { module = "dev.failsafe:failsafe", version.ref = "failsafe" }
junit = { module = "org.junit.jupiter:junit-jupiter", version.ref = "junit" }
truth = { module = "com.google.truth:truth", version.ref = "truth" }

[plugins]
versions = { id = "com.github.ben-manes.versions", version.ref = "versions" }
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-rc-3-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Loading

0 comments on commit 2c7b878

Please sign in to comment.