Quarkus Business Score

This extension offers a convenient way to detect application zombies, i.e. applications that live and communicate but do not produce any business value. The "business value" means anything that helps to solve a problem of an application user. Infrastructure stuff (logs, stats, metrics, health checks) usually does not produce a business value.

Key concepts

In a nutshell, this extension manages the business score which is a numeric representation of the business value. An application emits score records to increase the business score, either directly with the BusinessScore API or with an interceptor binding. The records are only kept for the specific amount of time - time window. The sum of all score records in the current time window is the current business score. The zombie threshold defines the point at which the application is considered a zombie. An external system or the application itself can periodically check the business score and react appropriately.

Core

If you want to use this extension, you need to add the io.quarkiverse.businessscore:quarkus-business-score extension first.

For instance, with Maven, add the following dependency to your POM file:

<dependency>
    <groupId>io.quarkiverse.businessscore</groupId>
    <artifactId>quarkus-business-score</artifactId>
    <version>1.0.0.Alpha4</version>
</dependency>

How to score

Quarkus provides a CDI bean of type io.quarkiverse.businessscore.BusinessScore that can be used to increase and also to query the current score.

BusinessScore example
import jakarta.enterprise.context.ApplicationScoped;
import io.quarkiverse.businessscore.BusinessScore;

@ApplicationScoped
public class MyService {

   @Inject
   BusinessScore bs; (1)

   public void doSomeBusiness() {
     bs.score(10); (2)
     // ...
   }

}
1 Inject the business score of the current application.
2 Increase the business score by 10.

Alternatively, the @io.quarkiverse.businessscore.Scored interceptor binding can be used to increase the score using an interceptor.

@Scored example
import
import io.quarkiverse.businessscore.BusinessScore;

@ApplicationScoped
public class MyService {

   @Scored(10) (1)
   public void doSomeBusiness() {
     // ...
   }

}
1 Increase the business score of the current application by 10.

How to check the business score

You can inject the io.quarkiverse.businessscore.BusinessScore and check the "zombie" status with the BusinessScore#test() method.

BusinessScore example
import jakarta.enterprise.context.ApplicationScoped;
import io.quarkiverse.businessscore.BusinessScore;

@ApplicationScoped
public class MyService {

   @Inject
   BusinessScore bs; (1)

   public void check() {
     if (bs.test().isZombie()) {
        // TODO warn the application admin!
     }
   }

}
1 Inject the business score of the current application.

HTTP module

This module integrates with the HTTP extension and registers two additional management endpoints:

  • /q/business-score - shows the current score, zombie status, etc.

  • /q/business-score/records - shows all score records in the current time window

<dependency>
    <groupId>io.quarkiverse.businessscore</groupId>
    <artifactId>quarkus-business-score-http</artifactId>
    <version>1.0.0.Alpha4</version>
</dependency>
/q/business-score response example
{
    "serverTime": "2024-06-13T15:14:20.794528118",
    "application": {
        "name": "quarkus-business-score-integration-tests",
        "version": "999-SNAPSHOT"
    },
    "zombie": false,
    "score": 1,
    "zombieThreshold": 20,
    "initialZombieThreshold": 10,
    "timeWindow": "PT72H",
    "initialTimeWindow": "PT168H"
}
/q/business-score/records response example
{
    "serverTime": "2024-06-13T15:14:21.259640872",
    "application": {
        "name": "quarkus-business-score-integration-tests",
        "version": "999-SNAPSHOT"
    },
    "records": [
        {
            "value": 1,
            "timestamp": "2024-06-13T13:14:20.735Z"
        },
        {
            "value": 1,
            "timestamp": "2024-07-13T13:14:20.135Z"
        }
    ]
}

Self-check module

This module integrates with the Scheduler extension and registers an additional @Scheduled method. The current application is tested periodically and if a zombie is detected then a warning message is logged and a CDI event of type io.quarkiverse.businessscore.BusinessScore.ZombieStatus is fired synchronously. The CRON trigger used to schedule an automatic self-check can be configured with the quarkus.business-score.self-check.cron configuration property.

<dependency>
    <groupId>io.quarkiverse.businessscore</groupId>
    <artifactId>quarkus-business-score-self-check</artifactId>
    <version>1.0.0.Alpha4</version>
</dependency>
CDI observer example
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.event.Observes;

@ApplicationScoped
public class MyService {

   void onZombie(@Observes BusinessScore.ZombieStatus status) { (1)
      // TODO warn the application admin!
   }

}
1 Observe the ZombieStatus and react appropriately.

If quarkus.business-score.self-check is set to true then the shutdown process is initiated when a zombie a zombie is detected.

Health module

This module integrates with the SmallRye Health extension and registers a @Wellness health check automatically. The name of the health check is business-score. It reports the status UP if the app is NOT considered a zombie. The health check is accessible through the /q/health/well endpoint.

<dependency>
    <groupId>io.quarkiverse.businessscore</groupId>
    <artifactId>quarkus-business-score-health</artifactId>
    <version>1.0.0.Alpha4</version>
</dependency>
/q/health/well response example
{
    "status": "UP",
    "checks": [
        {
            "name": "business-score",
            "status": "UP",
            "data": {
                "score": 0,
                "zombieThreshold": 10,
                "timeWindow": "PT10H"
            }
        }
    ]
}

Mailer module

This module integrates with the Mailer extension and sends an email automatically when a self-test perfomed by the Self-check module fails, i.e. when a zombie is detected. The from, to and subject fields are configurable.

<dependency>
    <groupId>io.quarkiverse.businessscore</groupId>
    <artifactId>quarkus-business-score-mailer</artifactId>
    <version>1.0.0.Alpha4</version>
</dependency>

Extension Configuration Reference

Configuration property fixed at build time - All other configuration properties are overridable at runtime

Configuration property

Type

Default

The point at which the application is considered a zombie.

An application is considered a zombie if the current score is below the threshold in the current time window.

Environment variable: QUARKUS_BUSINESS_SCORE_ZOMBIE_THRESHOLD

long

10

The amount of time a score record is kept alive.

By default, it is kept for one week.

Environment variable: QUARKUS_BUSINESS_SCORE_TIME_WINDOW

Duration

7D

The limit at which the extension will remove all records outside the current time window.

Environment variable: QUARKUS_BUSINESS_SCORE_AUTO_COMPACT_LIMIT

int

1000

About the Duration format

To write duration values, use the standard java.time.Duration format. See the Duration#parse() Java API documentation for more information.

You can also use a simplified format, starting with a number:

  • If the value is only a number, it represents time in seconds.

  • If the value is a number followed by ms, it represents time in milliseconds.

In other cases, the simplified format is translated to the java.time.Duration format for parsing:

  • If the value is a number followed by h, m, or s, it is prefixed with PT.

  • If the value is a number followed by d, it is prefixed with P.

Configuration property fixed at build time - All other configuration properties are overridable at runtime

Configuration property

Type

Default

The root path for management endpoints.

By default, this value is resolved as a path relative to quarkus.http.non-application-root-path. If the management interface is enabled, the value will be resolved as a path relative to quarkus.management.root-path.

Environment variable: QUARKUS_BUSINESS_SCORE_HTTP_ROOT_PATH

string

business-score

Configuration property fixed at build time - All other configuration properties are overridable at runtime

Configuration property

Type

Default

The CRON trigger used to schedule an automatic self-check.

If BusinessScore.ZombieStatus#isZombie() returns true then a warning message is logged and a CDI event of type BusinessScore.ZombieStatus is fired synchronously.

Environment variable: QUARKUS_BUSINESS_SCORE_SELF_CHECK_CRON

string

0 0 0/6 * * ?

If set to true then the shutdown process is initiated when BusinessScore.ZombieStatus#isZombie() returns true during the self-check.

Environment variable: QUARKUS_BUSINESS_SCORE_SELF_CHECK_AUTO_EXIT

boolean

false

Configuration property fixed at build time - All other configuration properties are overridable at runtime

Configuration property

Type

Default

The sender address.

Environment variable: QUARKUS_BUSINESS_SCORE_MAILER_FROM

string

required

The comma-separated list of recipients.

Environment variable: QUARKUS_BUSINESS_SCORE_MAILER_TO

string

required

The subject. The value is used as a Qute template with available data: appName and appVersion.

Environment variable: QUARKUS_BUSINESS_SCORE_MAILER_SUBJECT

string

[ZOMBIE DETECTED] {appName}:{appVersion}