L’interface est localisée ; les présentations et documents des Skills sont traduits automatiquement par IA dans votre langue. Le code, les commandes, chemins et termes techniques restent en version originale, et le document de l’auteur fait foi.
Explorer les Skills
Productivité · SKILL.md

microprofile

microprofile

MicroProfile specification reference covering Config, OpenAPI, Fault Tolerance, Metrics, Health, JWT Security, Open Telemetry, and Server Sent Events for cloud-native Java microservices.

Independent GitHub snapshot · Automated classification · Original documentation governs

Documentation de la Skill

GitHub

name: microprofile description: MicroProfile specification reference covering Config, OpenAPI, Fault Tolerance, Metrics, Health, JWT Security, Open Telemetry, and Server Sent Events for cloud-native Java microservices. license: MIT compatibility: opencode metadata: version: "1.0.0" domain: cncf triggers: microprofile, fault tolerance, service mesh, openapi spec, health checks, metrics endpoint, config source, jwt security metrics endpoint archetypes:

  • educational
  • strategic anti_triggers:
  • brainstorming
  • vague ideation
  • non-containerized architecture response_profile: verbosity: medium directive_strength: low abstraction_level: strategic role: reference scope: infrastructure output-format: manifests content-types:
  • guidance
  • examples
  • do-dont
  • config related-skills: jakarta-ee, jakarta-migration

MicroProfile for Cloud-Native Java

Implements and configures MicroProfile specifications to add cloud-native operational capabilities — externalized configuration, service mesh compatibility, observability (metrics, tracing, health), fault tolerance patterns, and JWT-based security — on top of Jakarta EE application servers or as part of native compilation with Quarkus.

TL;DR Checklist

  • Select only the MicroProfile features needed — avoid loading unnecessary specification overhead
  • Configure MicroProfile Config sources in priority order (env vars > system properties > config.properties > defaults)
  • Implement both liveness and readiness health checks for proper Kubernetes pod lifecycle management
  • Use @CircuitBreaker with appropriate thresholds to prevent cascading failures across services
  • Verify OpenAPI docs are generated and accessible at /openapi before exposing the service

Purpose and Use Cases

MicroProfile is a specification overlay on Jakarta EE focused exclusively on cloud-native microservice concerns. While Jakarta EE provides the enterprise platform (servlets, JPA, CDI, transactions), MicroProfile adds operational capabilities required for containerized, Kubernetes-deployed services.

Use MicroProfile when:

  • Deploying Jakarta EE applications to Kubernetes or other container orchestration platforms
  • Needing standardized health checks, metrics, and tracing across a microservice ecosystem
  • Implementing resilience patterns (circuit breaker, retry, timeout) consistently across services
  • Requiring externalized configuration with layered sources for multi-environment deployments
  • Building service-to-service communication with JWT-based authentication
  • Targeting Open Liberty, WildFly Payara Server, or Quarkus as runtime containers

Do not use MicroProfile when:

  • Running Jakarta EE applications on-premises without container orchestration needs
  • Using Spring Boot — it provides equivalent capabilities through Spring Cloud / Actuator natively
  • Building monolithic applications where operational concerns are managed at the infrastructure level

When to Use

Use this skill when:

  • Adding cloud-native operational features (health, metrics, config, fault tolerance) to a Jakarta EE application
  • Deploying services to Kubernetes and needing liveness/readiness probes for pod lifecycle management
  • Implementing distributed resilience patterns (circuit breaker, retry with backoff, timeout enforcement)
  • Configuring externalized configuration with layered sources across dev/staging/production environments
  • Setting up JWT-based authentication for inter-service communication in a microservice architecture
  • Integrating OpenTelemetry distributed tracing across Jakarta EE service boundaries
  • Building event-driven or streaming APIs using Server-Sent Events (SSE) on top of JAX-RS

When NOT to Use

Avoid this skill for:

  • Setting up Spring Boot Actuator — it provides equivalent health/metrics/tracing natively without MicroProfile
  • Developing a single-server monolith where operational concerns are handled at the infrastructure level
  • Building applications that don't need externalized configuration or resilience patterns
  • Adding cloud-native features to non-Java services (Go, Python, Node.js) — use their native ecosystems

Core Workflow

  1. Identify Required Specifications — List the MicroProfile specs needed for your deployment scenario:

    • Kubernetes health probes: MP Health (liveness + readiness)
    • Observability pipeline: MP Metrics + MP OpenTelemetry
    • Externalized config: MP Config with layered sources
    • Resilience patterns: MP Fault Tolerance (@CircuitBreaker, @Retry, @Timeout)
    • API documentation: MP OpenAPI for JAX-RS endpoints Checkpoint: Only add Maven dependencies for the specs you need — unused specs add classpath overhead.
  2. Add Dependencies and Activate Features — For each selected spec, add the corresponding Maven artifact. On OpenLiberty, also add features to server.xml. On WildFly, use feature-manager CLI commands. Quarkus auto-activates features from dependencies. Checkpoint: Verify the server logs show all enabled MicroProfile features during startup — missing activations cause silent runtime failures.

  3. Implement Health Checks — Create at least two health check classes: one annotated with @Liveness (process-alive indicator) and one with @Readiness (traffic-ready indicator). Aggregate dependency states (database, cache, external services) into composite checks. Checkpoint: Test both endpoints against localhost before deploying to Kubernetes — missing health probes cause pods to remain in Pending state.

  4. Configure Externalized Settings — Use @ConfigProperty annotations with explicit default values for all configuration. Define a priority-ordered config source chain: environment variables (highest) > system properties > application.properties > defaults. Prefix all property names with the service name. Checkpoint: Verify that required configurations are set in each deployment environment before enabling traffic to the pod.

  5. Deploy and Verify — Package as a WAR or JAR, deploy to the target container. Verify: health endpoints return JSON, metrics expose at /metrics, OpenAPI docs render at /openapi. Run integration tests against all MicroProfile endpoints. Checkpoint: Confirm Prometheus can scrape the metrics endpoint and that liveness/readiness probes trigger correct Kubernetes actions in a test namespace.


Architecture Overview

MicroProfile sits on top of Jakarta EE as a modular specification overlay. Each MicroProfile specification is independently implementable — an application only needs to enable the features it actually uses. The runtime (typically SmallRye) provides the implementation for each spec.

┌─────────────────────────────────────────────────────────┐
│                    Kubernetes / Cloud                    │
│    ┌─────────┐  ┌──────────┐  ┌──────────────────────┐  │
│    │  curl   │  │Prometheus│  │ Jaeger / Zipkin      │  │
│    │ /health │  │ scrape   │  │ tracing ingestion    │  │
│    └────┬────┘  └────┬─────┘  └──────────┬───────────┘  │
│         │             │                   │              │
└─────────┼─────────────┼───────────────────┼──────────────┘
          │ HTTP        │ HTTP              │ gRPC/HTTP
┌─────────▼─────────────▼───────────────────▼──────────────┐
│              MicroProfile Layer (Spec Overlay)             │
│  ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌────────────┐   │
│  │  Config  │ │  Health  │ │ Metrics  │ │  JWT       │   │
│  │  (MP3.1) │ │  (MP4.0) │ │  (MP3.2) │ │ Security  │   │
│  └────┬─────┘ └────┬─────┘ └────┬─────┘ └─────┬──────┘   │
│  ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌────────────┐   │
│  │ Fault    │ │ OpenAPI  │ │  SSE     │ │ Open       │   │
│  │ Tolerance│ │(MP3.1)   │ │  (MP2.0) │ │Telemetry  │   │
│  │(MP3.1)   │ └──────────┘ └──────────┘ │  (MP2.0)  │   │
│  └────┬─────┘                            └────────────┘   │
└─────────┼─────────────────────────────────────────────────┘
          │ CDI / Jakarta EE APIs
┌─────────▼─────────────────────────────────────────────────┐
│              Jakarta EE Container                          │
│  (WildFly, Payara, OpenLiberty, Quarkus)                   │
│  CDI · Servlet · JAX-RS · JPA · EJB · Interceptors       │
└───────────────────────────────────────────────────────────┘

Modular Activation

Each MicroProfile feature is activated independently by adding the appropriate Maven dependency. This means minimal overhead — you only pay for what you use:

<!-- Minimal MicroProfile setup — enable only what you need -->
<dependency>
    <groupId>org.eclipse.microprofile.config</groupId>
    <artifactId>microprofile-config-api</artifactId>
    <version>3.1</version>
</dependency>
<dependency>
    <groupId>org.eclipse.microprofile.health</groupId>
    <artifactId>microprofile-health-api</artifactId>
    <version>3.1</version>
</dependency>
<dependency>
    <groupId>org.eclipse.microprofile.fault-tolerance</groupId>
    <artifactId>microprofile-fault-tolerance-api</artifactId>
    <version>3.1</version>
</dependency>

MicroProfile Specifications Table

SpecificationCurrent VersionMaven ArtifactDescription
ConfigMP Config 3.1microprofile-config-apiExternalized configuration with layered sources (env vars, system properties, config.properties files), typed values, and validators
OpenAPIMP OpenAPI 3.1microprofile-openapi-apiAutomatic OpenAPI 3.0 specification generation from JAX-RS annotations, providing interactive API documentation
Fault ToleranceMP Fault Tolerance 3.1microprofile-fault-tolerance-apiResilience patterns: circuit breaker, retry with exponential backoff, timeout enforcement, bulkhead isolation
MetricsMP Metrics 3.2microprofile-metrics-apiPrometheus-compatible metrics export with counter, gauge, histogram, timer, and meter types
HealthMP Health 3.1microprofile-health-apiLiveness and readiness probes for Kubernetes pod lifecycle management and service mesh routing
JWT SecurityMP JWT 2.0microprofile-jwt-auth-apiJSON Web Token authentication and authorization, container-managed JWT extraction from HTTP headers
OpenTelemetryMP OpenTelemetry 2.0microprofile-opentelemetry-apiDistributed tracing with W3C Trace Context propagation across service boundaries
Server Sent EventsMP SSE 2.0microprofile-sse-apiServer-side streaming responses using the Server-Sent Events protocol
Rest ClientMP Rest Client 3.1microprofile-rest-client-apiType-safe declarative REST client interfaces with automatic JSON serialization and fault tolerance integration
MessagingMP Messaging 3.0microprofile-messaging-apiAsynchronous messaging using the MicroProfile Messaging pattern (Kafka, RabbitMQ adapters)
ConductRRetired—Service discovery for Lightbend ConductR — retired, replaced by Kubernetes-native approaches

Complete Working Examples

Example 1: Fault Tolerance — Combined Resilience Patterns

Combines @CircuitBreaker, @Retry, and @Timeout on a single service method. This pattern is the most common production configuration for inter-service communication:

package com.example.service;

import org.eclipse.microprofile.faulttolerance.*;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import java.time.Duration;
import java.util.Optional;

@ApplicationScoped
public class PaymentService {

    @Inject
    private PaymentGatewayClient gatewayClient;

    /**
     * Process payment with full resilience pattern:
     * - Retry up to 3 times with exponential backoff (1s, 2s, 4s) on failure
     * - Timeout after 5 seconds to prevent hung requests
     * - Circuit breaker opens after 5 consecutive failures, half-opens after 10s
     */
    @Retry(maxRetries = 3, delay = 1000, delayUnit = java.util.concurrent.TimeUnit.MILLISECONDS,
         maxDuration = Duration.ofSeconds(15), retryOn = {java.net.SocketTimeoutException.class})
    @CircuitBreaker(requestVolumeThreshold = 10, failureRatio = 0.5, delay = 10000,
                   successThreshold = 3, failureOn = {RuntimeException.class})
    @Timeout(value = 5)
    public PaymentResult processPayment(PaymentRequest request) {
        try {
            // Call downstream payment gateway with fault tolerance applied
            GatewayResponse response = gatewayClient.charge(request);

            if (response.statusCode() == 200 && response.transactionId() != null) {
                return new PaymentResult(
                    response.transactionId(),
                    request.amount(),
                    PaymentStatus.SUCCESS,
                    java.time.Instant.now()
                );
            } else {
                // Gateway returned non-success — retry is already configured via @Retry
                throw new RuntimeException("Payment gateway returned status: " + response.statusCode());
            }
        } catch (java.net.SocketTimeoutException e) {
            // Timeout is treated as a transient failure — triggers retry circuit
            throw new RuntimeException("Payment gateway timeout", e);
        } catch (java.io.IOException e) {
            // Network-level failures should also trigger retries
            throw new RuntimeException("Network error contacting payment gateway", e);
        }
    }

    /**
     * Check payment status — lightweight call that doesn't need circuit breaker.
     * Only uses timeout to prevent hanging on a slow response.
     */
    @Timeout(value = 3)
    public Optional<PaymentResult> getPaymentStatus(String transactionId) {
        try {
            GatewayResponse response = gatewayClient.status(transactionId);
            if (response.statusCode() == 200 && response.data() != null) {
                return Optional.of(mapToResult(response));
            }
            return Optional.empty();
        } catch (Exception e) {
            // Don't trigger circuit breaker for status checks — they're low-impact
            throw new RuntimeException("Failed to retrieve payment status", e);
        }
    }

    private PaymentResult mapToResult(GatewayResponse response) {
        return new PaymentResult(
            response.transactionId(),
            response.amount(),
            parseStatus(response.status()),
            java.time.Instant.now()
        );
    }

    private PaymentStatus parseStatus(String statusString) {
        try {
            return PaymentStatus.valueOf(statusString.toUpperCase());
        } catch (IllegalArgumentException e) {
            return PaymentStatus.UNKNOWN;
        }
    }

    public record PaymentResult(
        String transactionId,
        java.math.BigDecimal amount,
        PaymentStatus status,
        java.time.Instant processedAt
    ) {}

    public enum PaymentStatus { SUCCESS, FAILURE, PENDING, UNKNOWN }
}

Example 2: Health Checks — Liveness and Readiness

Proper health checks are essential for Kubernetes pod management. Liveness determines if the process is alive; readiness determines if it can accept traffic:

package com.example.health;

import org.eclipse.microprofile.health.*;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import java.time.Duration;
import java.time.Instant;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@ApplicationScoped
public class ApplicationHealthChecker {

    @Inject
    private DatabaseConnectionChecker databaseChecker;

    // Track liveness state — set to false if a fatal error occurs that cannot be recovered from
    private volatile boolean isAlive = true;
    private final Map<String, Instant> lastStartupTimes = new ConcurrentHashMap<>();

    /**
     * Liveness probe: Is the application process running and not in a corrupted state?
     * Kubernetes kills and restarts pods that fail liveness checks.
     */
    @Liveness
    public HealthCheckResponse getLivenessStatus() {
        if (!isAlive) {
            return HealthCheckResponse.named("application-liveness")
                .withData("state", "crashed")
                .withData("lastError", "Unrecoverable state detected")
                .down()
                .build();
        }

        boolean dbConnected = databaseChecker.isConnected();
        
        if (!dbConnected) {
            return HealthCheckResponse.named("database-liveness")
                .withData("connectionStatus", "lost")
                .down()
                .build();
        }

        return HealthCheckResponse.named("application-liveness")
            .withData("state", "running")
            .withData("uptime", Duration.between(lastStartupTimes.getOrDefault("start", Instant.now()), Instant.now()).toSeconds())
            .withData("database", dbConnected ? "connected" : "disconnected")
            .up()
            .build();
    }

    /**
     * Readiness probe: Is the application ready to accept traffic?
     * Kubernetes removes pods from service load balancing when readiness fails.
     */
    @Readiness
    public HealthCheckResponse getReadinessStatus() {
        boolean dbConnected = databaseChecker.isConnected();
        boolean cacheWarm = checkCacheWarmth();

        if (!dbConnected) {
            return HealthCheckResponse.named("service-readiness")
                .withData("database", "disconnected")
                .notReady()
                .build();
        }

        if (!cacheWarm) {
            // Not ready until cache is warmed — important for cold starts after scaling events
            return HealthCheckResponse.named("cache-readiness")
                .withData("cacheStatus", "warming")
                .notReady()
                .build();
        }

        return HealthCheckResponse.named("service-readiness")
            .withData("database", "connected")
            .withData("cache", "warm")
            .withData("readyToServeTraffic", true)
            .up()
            .build();
    }

    private boolean checkCacheWarmth() {
        // In production, this would check a proper cache initialization state
        return lastStartupTimes.values().stream()
            .anyMatch(t -> Duration.between(t, Instant.now()).toSeconds() > 30);
    }

    /**
     * Mark the application as alive — call during startup completion.
     * This is a deliberate liveness signal that survives container restarts.
     */
    public void markAlive() {
        this.isAlive = true;
        this.lastStartupTimes.put("start", Instant.now());
    }

    /**
     * Mark the application as crashed — call from error handlers for unrecoverable errors.
     * This triggers Kubernetes to restart the pod automatically.
     */
    public void markCrashed(String reason) {
        this.isAlive = false;
        // Log the crash reason for debugging
        System.err.println("CRITICAL: Application marked as crashed: " + reason);
    }
}

Example 3: OpenAPI Documentation

Auto-generates OpenAPI 3.0 specification from JAX-RS annotations — no manual API docs required:

package com.example.resource;

import org.eclipse.microprofile.openapi.annotations.*;
import org.eclipse.microprofile.openapi.annotations.enums.*;
import org.eclipse.microprofile.openapi.annotations.media.*;
import org.eclipse.microprofile.openapi.annotations.parameters.*;
import org.eclipse.microprofile.openapi.annotations.responses.*;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;

@OpenAPIDefinition(
    info = @Info(
        title = "User Management API",
        version = "1.0.0",
        description = "RESTful API for managing user accounts and profiles in the platform.",
        contact = @Contact(name = "API Support", email = "api-support@example.com"),
        license = @License(name = "MIT", url = "https://opensource.org/licenses/MIT")
    ),
    tags = {
        @Tag(name = "users", description = "User account operations"),
        @Tag(name = "admin", description = "Administrative user operations")
    }
)
@Path("api/v1/users")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class UserResource {

    /**
     * Retrieve all users with pagination support.
     */
    @GET
    @Operation(
        summary = "List all users",
        description = "Returns a paginated list of users ordered by creation date.",
        tags = {"users"},
        responses = {
            @ApiResponse(
                responseCode = "200",
                description = "Successfully returned user list",
                content = @Content(
                    array = @ArraySchema(
                        schema = @Schema(implementation = UserDTO.class)
                    ),
                    examples = @ExampleObject(
                        name = "Sample users",
                        value = "[{\"id\":1,\"username\":\"alice\",\"email\":\"alice@example.com\"}]"
                    )
                )
            ),
            @ApiResponse(responseCode = "500", description = "Internal server error")
        }
    )
    @Parameter(name = "page", description = "Page number (1-indexed)", in = ParameterIn.QUERY, schema = @Schema(defaultValue = "1"))
    @Parameter(name = "limit", description = "Items per page (max 100)", in = ParameterIn.QUERY, schema = @Schema(defaultValue = "20", maximum = "100"))
    public Response listUsers(
        @QueryParam("page") @DefaultValue("1") int page,
        @QueryParam("limit") @DefaultValue("20") int limit
    ) {
        // Implementation delegated to service layer
        return Response.ok(java.util.Collections.emptyList()).build();
    }

    /**
     * Create a new user account.
     */
    @POST
    @Operation(
        summary = "Create a new user",
        description = "Creates a new user account and returns the created resource with its assigned ID.",
        tags = {"users"},
        requestBody = @RequestBody(
            required = true,
            content = @Content(
                schema = @Schema(implementation = UserCreateRequest.class),
                examples = {
                    @ExampleObject(
                        name = "Standard creation",
                        value = "{\"username\":\"bob\",\"email\":\"bob@example.com\"}"
                    ),
                    @ExampleObject(
                        name = "With role assignment",
                        value = "{\"username\":\"admin-user\",\"email\":\"admin@example.com\",\"role\":\"ADMIN\"}"
                    )
                }
            )
        ),
        responses = {
            @ApiResponse(
                responseCode = "201",
                description = "User created successfully",
                content = @Content(schema = @Schema(implementation = UserDTO.class))
            ),
            @ApiResponse(
                responseCode = "409",
                description = "Username already exists",
                content = @Content(schema = @Schema(implementation = ErrorResponse.class))
            )
        }
    )
    public Response createUser(UserCreateRequest request) {
        return Response.status(Response.Status.CREATED).build();
    }

    public record UserDTO(Long id, String username, String email, String role) {}
    public record UserCreateRequest(String username, String email, String role) {}
    public record ErrorResponse(String message) {}
}

Example 4: MicroProfile Config — Externalized Configuration

Inject configuration from multiple sources with typed values and validation:

package com.example.config;

import org.eclipse.microprofile.config.inject.ConfigProperty;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import java.time.Duration;
import java.util.Optional;

@ApplicationScoped
public class ServiceConfiguration {

    /**
     * Inject configuration from layered sources.
     * Priority: System properties > Environment variables > config.properties > default value
     * 
     * Example env var: SERVICE_RETRY_DELAY=5000
     */
    @ConfigProperty(name = "payment.retry.delay", defaultValue = "1000")
    int retryDelayMs;

    /**
     * Typed configuration with explicit type coercion.
     * Can be set via: PAYMENT_TIMEOUT_SECONDS=30
     */
    @ConfigProperty(name = "payment.timeout.seconds", defaultValue = "10")
    Duration paymentTimeout;

    /**
     * Optional configuration — no error if the property is not set anywhere.
     * Falls back to null, never throws.
     */
    @ConfigProperty(name = "payment.gateway.url")
    Optional<String> gatewayUrl;

    /**
     * Boolean configuration — auto-coerced from strings ("true", "yes", "1" all work).
     */
    @ConfigProperty(name = "payment.enabled", defaultValue = "true")
    boolean paymentEnabled;

    /**
     * Custom config source can override default values at runtime.
     * For example, a custom ConfigSource could read from Vault or Consul.
     */
    public int getRetryDelayMs() {
        return retryDelayMs;
    }

    public Duration getPaymentTimeout() {
        return paymentTimeout;
    }

    public String getGatewayUrlOrDefault(String fallback) {
        return gatewayUrl.orElse(fallback);
    }

    public boolean isPaymentEnabled() {
        return paymentEnabled;
    }
}

Reference Implementation Guidance

SmallRye — Default MicroProfile Implementation

SmallRye is the reference implementation for most MicroProfile specifications. It integrates with each major Jakarta EE server:

ServerSmallRye IntegrationActivation Method
OpenLibertyBuilt-in — no additional dependencies neededAdd features to server.xml: <feature>microprofile-faultTolerance-3.1</feature>
WildFlyOptional feature via WildFly Swarm / overlayInstall the MicroProfile subsystem: jboss-cli.sh --command="feature-manager add microprofile-fault-tolerance-3.1"
Payara ServerIncluded by default in Payara Platform 6+No configuration needed — all MicroProfile features auto-activate when APIs are on classpath
QuarkusNative MicroProfile implementation optimized for GraalVMEnable via application.properties: quarkus.smallrye-fault-tolerance.enabled=true

Quarkus Native Compilation Considerations

When compiling Jakarta EE + MicroProfile applications to native images with GraalVM, additional configuration is needed:

# application.properties — Quarkus native compilation config
quarkus.native.additional-build-args=\
  -H:ReflectionConfigurationFiles=reflection-config.json,\
  -H:ResourceConfigurationFiles=resource-config.json

# Register beans for reflection (required for CDI proxy generation)
# src/main/resources/reflection-config.json
[
  {
    "name": "com.example.service.PaymentService",
    "allPublicMethods": true,
    "allPublicFields": true
  }
]

# MicroProfile specific native config
quarkus.smallrye-openapi.store-schema-directory=target/openapi
quarkus.smallrye-metrics.enabled=true

Common Pitfalls

PitfallCausePrevention
Fault tolerance transaction boundary conflicts@CircuitBreaker and @Retry on a method with @TransactionAttribute.REQUIRED causes the transaction to participate in the retry loopKeep fault tolerance annotations on methods that do NOT begin new JTA transactions; put them on the service facade and let the EJB/CDI bean manage transactions separately
Health check false positives causing pod restartsReadiness checks passing even when critical dependencies are degradedImplement layered health checks — separate liveness (process-alive) from readiness (traffic-ready); use composite health checks that aggregate multiple dependency states
Metrics naming collisions across servicesMultiple services exporting metrics with identical names to the same Prometheus instanceUse service-specific metric prefixes: my_service_http_requests_total instead of just http_requests_total. Configure via MicroProfile Metrics custom naming.
Config source priority confusionEnvironment variables silently override application-default config.properties values, causing unexpected behavior in different deployment environmentsDocument the full config source priority order; use unique property names with service prefixes (e.g., payment.retry.delay instead of retry.delay)
OpenAPI duplicationMultiple JAX-RS resource classes define overlapping @OpenAPIDefinition annotations that merge incorrectlyDefine OpenAPI metadata at a single entry point or use package-level @OpenAPIDefinition; avoid annotating individual methods with tag definitions

Constraints

MUST DO

  • Implement both liveness and readiness health checks — Kubernetes needs both for correct pod lifecycle management
  • Use MicroProfile Config with explicit default values for all required configuration — never rely on properties being present at runtime
  • Prefix fault tolerance annotations only on public, non-transactional service facade methods to avoid JTA transaction conflicts
  • Register metrics with descriptive names that include the service name to prevent collisions across a multi-service deployment
  • Generate and review OpenAPI documentation at /openapi before each release — it is the source of truth for API consumers

MUST NOT DO

  • Disable or bypass circuit breakers in production — they are essential for preventing cascading failures in distributed systems
  • Use @CircuitBreaker on database persistence methods — combine fault tolerance with transaction management only at the service boundary
  • Place @Timeout on methods that perform long-running batch operations without measuring actual execution time first
  • Mix MicroProfile Config property names across different namespaces (e.g., timeout vs payment.timeout) — use a consistent naming convention throughout
  • Deploy to production with unvalidated MicroProfile Config — missing required properties cause runtime failures, not startup errors

Output Template

When implementing or reviewing a MicroProfile-enabled Jakarta EE application, produce:

  1. Feature Inventory — List of all active MicroProfile specifications with their enabled versions
  2. Configuration Map — Complete mapping of @ConfigProperty names to their deployment sources (env vars, properties, defaults)
  3. Health Check Analysis — Liveness and readiness definitions with dependency aggregation logic
  4. Fault Tolerance Plan — Circuit breaker thresholds, retry policies, and timeout values per service method
  5. Metrics Register — All metric names, types, and their corresponding application events

Related Skills

SkillPurpose
jakarta-eeBase platform reference for Jakarta EE specifications that MicroProfile extends with cloud-native capabilities
jakarta-migrationMigration guide for moving existing Java EE 8 applications to Jakarta EE before adding MicroProfile features

Live References

Authoritative documentation for MicroProfile specifications and implementations.

Skills enregistrées