Starter Web¶
The module sda-commons-starter-web provides several features to create a service based on the SDA
core concepts.
Configuration¶
| Property | Description | Default | Example | Env | 
|---|---|---|---|---|
| auth.issuersstring | Comma separated string of open id discovery key sources with required issuers. | https://iam-int.dev.de/auth/realms/123 | AUTH_ISSUERS | |
| auth.disableboolean | Disables authorization checks completely. | false | true | AUTH_DISABLE | 
| opa.disableboolean | Disables authorization checks with Open Policy Agent completely. In this case access to all resources is granted but no constraints are provided. | false | true | OPA_DISABLE | 
| opa.base.urlstring | The baseUrl of the Open Policy Agent Server. | "http://localhost:8181" | "http://opa-service:8181" | OPA_BASE_URL | 
| opa.policy.packagestring | The policy package to check for authorization. The policy must return the property allowas boolean as access decision and may return additional properties as constraints. | the package of the application class, be aware that moving the class causes a breaking change regarding deployment if the package is not explicitly set. | "com.custom.package.name" | OPA_POLICY_PACKAGE | 
| opa.exclude.patternsstring | Custom excluded paths can be configured as comma separated list of regex. | openapi.jsonandopenapi.yaml | "/customPathOne,/customPathTwo" | OPA_EXCLUDE_PATTERNS | 
| opa.client.connection.timeoutstring | The connection timeout of the client that calls the Open Policy Agent server. | "500ms" | "2s" | OPA_CLIENT_CONNECTION_TIMEOUT | 
| opa.client.timeoutstring | The read timeout of the client that calls the Open Policy Agent server. | "500ms" | "2s" | OPA_CLIENT_TIMEOUT | 
| oidc.client.enabledboolean | Enables OIDC Authentication (Client Credentials Flow) for the configured clients. | false | true | OIDC_CLIENT_ENABLED | 
| oidc.client.idstring | The client ID for the registration. | "exampleClient" | OPA_CLIENT_ID | |
| oidc.client.secretstring | The Client secret of the registration. | "s3cret" | OIDC_CLIENT_SECRET | |
| oidc.client.issuer.uristring | URI that can either be an OpenID Connect discovery endpoint or an OAuth 2.0 Authorization Server Metadata endpoint defined by RFC 8414. | "https://keycloak.sdadev.sda-se.io/auth/realms/exampleRealm" | OIDC_CLIENT_ISSUER_URI | |
| oidc.client.authentication-passthrough.enabledstring | Flag indicating whether the token from the existing request context should be used, if exists, before attempting to generate new one | true | false | OIDC_CLIENT_AUTHENTICATION_PASSTHROUGH_ENABLED | 
| cors.allowed-origin-patternsstring | Comma separated list of URL patterns for which CORS requests are allowed. | none allowed | "https://*.all-subdomains.com, https://static-domain.com" | CORS_ALLOWEDORIGINPATTERNS | 
| enable.json.loggingboolean | If logs should be printed as JSON. Note: This config param is not available for application.properties or application.yaml | false | true | ENABLE_JSON_LOGGING | 
| management.otlp.tracing.endpointstring | Base url to OTLP Collector instance. It applies for http or gRPC, if enabled | http://grafana-agent-traces.monitoring:4317 | "http://localhost:4318" | MANAGEMENT_OTLP_TRACING_ENDPOINT | 
| management.tracing.enabledboolean | If tracing should be unit-tested, it is important to have the annotation @AutoConfigureObservabilityon your test class to enable tracing. | true(falsein test contexts) | false | MANAGEMENT_TRACING_ENABLED | 
| management.tracing.sampling.probabilitynumber | Probability in the range from 0.0 to 1.0 that a trace will be sampled. | 1.0 | 0.2 | MANAGEMENT_TRACING_SAMPLING_PROBABILITY | 
| management.tracing.propagation.typestring | Tracing context propagation types produced and consumed by the application. Setting this property overrides the more fine-grained propagation type properties. | "b3,w3c" | "b3" | MANAGEMENT_TRACING_PROPAGATION_TYPE | 
| management.tracing.grpc.enabledboolean | You only need to set this property to true if you want to use grpc (port 4317) vs http (port 4318) channel for span export. | true | false | MANAGEMENT_TRACING_GRPC_ENABLED | 
| management.otlp.tracing.compressionstring | Method used to compress the payload. Options: "gzip", "none" | "none" | "gzip" | MANAGEMENT_OTLP_TRACING_COMPRESSION | 
| management.otlp.tracing.timeoutstring | Call timeout for the OTel Collector to process an exported batch of data. This timeout spans the entire call. | "10s" | "20s" | MANAGEMENT_OTLP_TRACING_TIMEOUT | 
| spring.application.namestring | The application name, also used for tracing. For PR deployments, you need to make sure it will have the PR suffix to distinguish tracings. | "application" | "my-service-name" | SPRING_APPLICATION_NAME | 
| only as environment variable | Field names as comma separated String in communication (e.g. HTTP headers), that are included in the metadata context of a process. | "ab-variant,landing-page" | METADATA_FIELDS | |
| security.validation-exception-handler-enabled | Allow to turn off ValidationExceptionHandler which is handling http status of responses when validation fails. defaults to true if omitted. | true | false | SECURITY_VALIDATION_EXCEPTION_HANDLER_ENABLED | 
For further information have a look at the Spring Boot documentation.
Default configuration set by this library
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |  | 
Please make sure to configure spring.application.name for every service.
Authentication¶
Enables feature that make a Spring Boot service compliant with the SDA SE Authentication concepts using OIDC.
OIDC Authentication can be configured with auth.issuers to provide a comma separated
list of trusted issuers. In develop and test environments, the boolean auth.disable may
be used to disable authentication.
The JWKS URI of each issuer is updated when an unknown Key ID is received and every 5 minutes. The cache of known JWK is invalidated after 15 minutes.
Warning
This setup allows authenticated and anonymous requests! It is the responsibility of policies provided by the Open Policy Agent to decide about denying anonymous requests.
Spring Security is disabled for the Management/Admin Port (default: 8081). Be aware that these port should not be accessible out of the deployment context.
This security implementation lacks some features compared to sda-dropwizard-commons:
- No configuration of static local public keys to verify the token signature. 
- No configuration of JWKS URIs to verify the token signature. 
- The IDP must provide an iss claim that matches the base URI for discovery. 
- Clock skew is fixed to 60 seconds. 
- The client that loads the JWKS is not configurable yet.
Authorization¶
Enables feature that make a Spring Boot service compliant with the SDA SE Authorization concepts using Open Policy Agent.
The authorization is done by the Open Policy Agent. It can be 
configured with opa. configuration properties.
Requests to the Open Policy Agent
Requests to the server are determined by the base URL and the policy package.
Given the default base URL http://localhost:8181 and an example package of com.my.service,
the Open Policy Agent server will be requested for authorization decision at
http://localhost:8181/v1/data/com/my/service.
The OPA configuration acts as a client to the Open Policy Agent and is hooked in as request filter
which is part of the SecurityFilterChain including the OIDC Authentication.
Constraints provided with the Open Policy Agent response can be mapped to a custom POJO.
The class must extend org.sdase.commons.spring.boot.web.auth.opa.AbstractConstraints and must be
annotated with org.sdase.commons.spring.boot.web.auth.opa.Constraints.
It has request scope and can be @Autowired 
in @Controllers 
or @RestControllers.
Custom Constraint implementation
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |  | 
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |  | 
| 1 2 3 4 5 6 |  | 
Additional parameters that are needed for the authorization decision may be provided with custom
org.sdase.commons.spring.boot.web.auth.opa.extension.OpaInputExtensions.
Testing¶
The testing module provides aligned test dependencies including Wiremock for external APIs and JUnit extensions to mock or disable authentication and authorization.
OPA¶
The OPA configuration requests the policy decision providing the following inputs
| Property | Description | Example | 
|---|---|---|
| input.httpMethod | HTTP method as uppercase string. | "GET" | 
| input.path | Requested path as array of path segments without context or servlet path. | ["myResource", "123-id", "someSubresource"] | 
| input.jwt | Validated encoded JWT as string (if available). | "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxIn0.Xpk63zUfXiI5f_bdGjqrhx03aGyBn9ETgXbkAgLalPk" | 
| input.headers | All HTTP request headers as object with lower-case header names as key and array of headers as value. | {"accept": "text/plain", "accept": "application/json"} | 
Security note
While a service might only consider one value of a specific header, that a policy might authorize on an array of those or vice versa. Consider this in your policy when you want to make sure you authorize on the same value that a service might use to evaluate the output.
Remark to HTTP request headers
The configuration normalizes header names to lower case to simplify handling in OPA since HTTP specification defines header names as case-insensitive. Multivalued headers are not normalized with respect to the representation as list or single string with separator char. They are forwarded as parsed by the framework.
Example Policy Using Input
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |  | 
| 1 2 3 4 5 6 7 8 |  | 
Http Client¶
Enables support for org.springframework.cloud.openfeign.FeignClients 
that support SDA Platform features like:
- passing the Authorization header to downstream services. - passing the Trace-Token header to downstream services. - OIDC client authentication
A feign client can be created as interface like this:
| 1 2 3 4 5 |  | 
@EnableFeignClients in order for the component 
scanning to pick up the @FeignClient annotated interfaces like so
| 1 2 3 4 |  | 
The Partner ODS base url must be configured as http://partner-ods:8080/api in the Spring
environment property partnerOds.baseUrl. Detailed configuration like timeouts can be configured
with default feign properties 
in the application.yaml or derived environment properties based on the name attribute of the 
org.springframework.cloud.openfeign.FeignClient 
annotation.
The client is then available as bean in the Spring context.
Authentication forwarding¶
The client can be used within the SDA Platform to path through the received authentication header by adding a configuration:
| 1 2 3 4 5 6 7 8 9 |  | 
org.sdase.commons.spring.boot.web.client.AuthenticationPassThroughClientConfiguration will take
the Authorization header from the current request context of the servlet and adds its value to
the client request.
Trace-Token¶
The client can be used within the SDA Platform to pass through the received Trace-Token header by adding a configuration:
| 1 2 3 4 5 6 7 8 9 |  | 
org.sdase.commons.spring.boot.web.tracing.SdaTraceTokenClientConfiguration will take the
Trace-Token header from the current request context of the servlet and adds its value to the
client request.
If no Trace-Token header is present in the current request context, the
SdaTraceTokenClientConfiguration will generate a new Trace-Token and pass it to the following
requests.
OIDC Client¶
If the request context is not always existing, e.g. in cases where a technical user for
service-to-service communication is required, the
.org.sdase.commons.spring.boot.web.client.OidcClientRequestConfiguration will request the required
OIDC authentication token with the client credentials flow using the configured
"oidc.client.issuer.uri", "oidc.client.id" and "oidc.client.secret".
If the current request context contains the Authorization header, the authentication
pass-through will be applied instead, in case "oidc.client.authentication-passthrough.enabled" flag is enabled.
JAX-RS Mapping¶
If you would like to use JAX-RS based web annotations, you just need to apply
the feign.jaxrs.JakartaContract.class to configurations.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |  | 
Platform Client¶
The PlatformClient combines the authentication forwarding, trace token and OIDC configuration
without the need to configure each individually.
| 1 2 3 4 5 6 7 |  | 
It abstracts some configuration of the FeignClient and is then available as bean as well.
Error Handling¶
The module sda-commons-starter-web provides a shared ApiError model, to provide a common
response error structure for SDA-restful services.
Usage¶
Per default, the module sda-commons-starter-web autoconfigures a
global @ExceptionHandler(ApiException.class) as @ControllerAdvice. As a result, the
exception handler is per default provided to every @Controller.
Referencing in OpenAPI¶
To provide the common ApiError in the API, you need to reference the class as @Schema.
| 1 2 3 4 5 |  | 
Throwing ApiException¶
When the ApiException is thrown the @ExceptionHandler automatically intercepts the exception and
maps the related ResponseEntity. As the result, the controller returns the related http response
code and the nested ApiError.
| 1 2 3 4 5 6 |  | 
In this example the controller would return with http status 422 and body:
| 1 2 3 4 5 6 7 8 9 10 |  | 
Actuator endpoints (Tasks)¶
Similar to dropwizards tasks, spring-boot provides actuators to expose endpoints on the management
port to monitor or interact with the application on an administrative level. The most basic example
for this is the /health endpoint which provides information about the status of the service.
Implementing custom actuator endpoints¶
Custom actuator endpoints can be registered with with the @Endpoint annotation:
| 1 2 3 4 |  | 
This will expose the endpoint under http://{SERVICE}:{MANAGEMENT_PORT}/custom, where the
id of the endpoint correlates with the path.
NOTE:
The default path for actuator endpoints in spring-boot is /actuator/. However, in sda-spring-boot-commons
it is configured to just /. See configuration of management.endpoints.web.base-path
GET, POST and DELETE methods can then be implemented with the according @ReadOperation, @WriteOperation
and @DeleteOperation:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |  | 
Actuators can then be enabled or disabled through the application properties
| 1 |  | 
See the official spring-boot documentation for further details.
Async¶
The default Spring async task executor is autoconfigured to transfer the request attributes of the current request to the Thread running the asynchronous method.
Jackson¶
Enables feature that makes a Spring Boot service compliant with the REST guide of SDA SE.
So far this covers:
- the tolerant reader pattern
- consistent serialization of java.time.ZonedDateTime compatible to the type date-time of JSON-Schema.
  It is strongly recommended to use
  - java.time.LocalDate for dates without time serialized as 2018-09-23
  - java.time.ZonedDateTime for date and times serialized as 2018-09-23T14:21:41+01:00
  - java.time.Duration for durations with time resolution serialized as P1DT13M
  - java.time.Period for durations with day resolution serialized as P1Y2D
All these types can be read and written in JSON as ISO 8601 formats.
Reading java.time.ZonedDateTime is configured to be tolerant so that added nanoseconds or missing
milliseconds or missing seconds are supported.
@com.fasterxml.jackson.annotation.JsonFormat(pattern = "...") should not be used for customizing
serialization because it breaks tolerant reading of formatting variants. If a specific field should
be serialized with milliseconds, it must be annotated with
@com.fasterxml.jackson.databind.annotation.JsonSerialize(using = Iso8601Serializer.WithMillis.class)
. If a specific field should be serialized with nanoseconds, it must be annotated with
@com.fasterxml.jackson.databind.annotation.JsonSerialize(using = Iso8601Serializer.WithNanos.class)
Differences to the known SDA Dropwizard Commons configuration
- java.time.ZonedDateTime fields are serialized with seconds by default.
  There is no other global configuration for java.time.ZonedDateTime serialization available.
- Fewer modules are activated for foreign frameworks. Compared to SDA Dropwizard Commons,
  GuavaExtrasModule, JodaModule, and CaffeineModule are not registered anymore.
- No documented customization of the global com.fasterxml.jackson.databind.ObjectMapper is available right now.
- Support for HAL Links and embedding linked resources is not implemented.
- Support for YAML is not implemented.
- There is no support for field filters.
  Such filters have been barely used in the SDA SE.
Monitoring¶
Services use Prometheus to scrape and store metrics.
An actuator exposing metrics in prometheus format is available using the following endpoint
| 1 |  | 
Spring Boot is using micrometer to instrument code using out-of-the-box bindings for common libraries.
SDA specific metrics¶
| Metric Name | Labels | Description | 
|---|---|---|
| healthcheck_status | name | Exposes healthcheck as metric for multiple indicators | 
JVM and System metrics¶
| Metric Name | Labels | Description | 
|---|---|---|
| jvm_classes_loaded_classes | The number of classes that are currently loaded in the Java virtual machine. | |
| jvm_classes_unloaded_classes | The total number of classes unloaded since the Java virtual machine has started execution. | |
| jvm_buffer_count_buffers | id | An estimate of the number of buffers in the pool. | 
| jvm_buffer_memory_used_bytes | id | An estimate of the memory that the Java virtual machine is using for this buffer pool. | 
| jvm_buffer_total_capacity_bytes | id | An estimate of the total capacity of the buffers in this pool. | 
| jvm_memory_used_bytes | id,area | The amount of used memory. | 
| jvm_memory_committed_bytes | id,area | The amount of memory in bytes that is committed for the Java virtual machine to use. | 
| jvm_memory_max_bytes | id,area | The maximum amount of memory in bytes that can be used for memory management. | 
| jvm_memory_usage_after_gc | The amount of memory used by the JVM after garbage collection (GC) has occurred. | |
| jvm_gc_max_data_size_bytes | Max size of long-lived heap memory pool. | |
| jvm_gc_live_data_size_bytes | Size of long-lived heap memory pool after reclamation. | |
| jvm_gc_memory_allocated_bytes_total | Incremented for an increase in the size of the (young) heap memory pool after one GC to before the next. | |
| jvm_gc_memory_promoted_bytes_total | Count of positive increases in the size of the old generation memory pool before GC to after GC. | |
| jvm_gc_concurrent_phase_time_seconds_count | gc,action,cause | Time spent in concurrent phase. | 
| jvm_gc_concurrent_phase_time_seconds_sum | gc,action,cause | |
| jvm_gc_concurrent_phase_time_seconds_max | gc,action,cause | |
| jvm_gc_pause_seconds_count | gc,action,cause | Time spent in GC pause. | 
| jvm_gc_pause_seconds_sum | gc,action,cause | |
| jvm_gc_pause_seconds_max | gc,action,cause | |
| jvm_gc_overhead | The percentage of total CPU time that is spent in garbage collection activities. | |
| system_cpu_count | The number of processors available to the Java virtual machine. | |
| system_load_average_1m | The sum of the number of runnable entities queued to available processors and the number of runnable entities running on the available processors averaged over a period of time. | |
| system_cpu_usage | The "recent cpu usage" of the system the application is running in. | |
| process_cpu_usage | The "recent cpu usage" for the Java Virtual Machine process. | |
| jvm_threads_peak_threads | The peak live thread count since the Java virtual machine started or peak was reset. | |
| jvm_threads_daemon_threads | The current number of live daemon threads. | |
| jvm_threads_live | The current number of live threads including both daemon and non-daemon threads. | |
| jvm_threads_started_threads_total | The total number of application threads started in the JVM. | |
| jvm_threads_states_threads | state | The current number of threads. | 
Key Metrics for monitoring Kafka¶
| Metric name | Labels | Description | 
|---|---|---|
| kafka_producer_compression_rate_avg | client.id | The average compression rate of record batches, defined as the average ratio of the compressed batch size over the uncompressed size. | 
| kafka_producer_response_rate | client.id | The number of responses received per second | 
| kafka_producer_request_rate | client.id | The number of requests sent per second | 
| kafka_producer_request_latency_avg | client.id | The average request latency in ms | 
| kafka_producer_outgoing_byte_rate | client.id | The number of outgoing bytes sent to all servers per second | 
| kafka_producer_io_wait_time_ns_avg | client.id | The average length of time the I/O thread spent waiting for a socket ready for reads or writes in nanoseconds. | 
| kafka_producer_batch_size_avg | client.id | The average number of bytes sent per partition per-request. | 
| kafka_consumer_records_lag | client.id | Number of messages consumer is behind producer on this partition | 
| kafka_consumer_records_lag_max | client.id | Maximum number of messages consumer is behind producer, either for a specific partition or across all partitions on this client | 
| kafka_consumer_bytes_consumed_rate | client.id | Average number of bytes consumed per second for a specific topic or across all topics. | 
| kafka_consumer_records_consumed_rate | client.id | Average number of records consumed per second for a specific topic or across all topics | 
| kafka_consumer_fetch_rate | client.id | Number of fetch requests per second from the consumer | 
MongoDB metrics¶
| Metric name | Labels | Description | 
|---|---|---|
| mongodb_driver_pool_waitqueuesize | cluster_id,server_address | The current size of the wait queue for a connection from the pool | 
| mongodb_driver_pool_checkedout | cluster_id,server_address | The count of connections that are currently in use | 
| mongodb_driver_pool_size | cluster_id,server_address | The current size of the connection pool, including idle and and in-use members | 
| mongodb_driver_commands_seconds_max | cluster_id,server_address,collection,command,status | Timer of mongodb commands | 
| mongodb_driver_commands_seconds_count | cluster_id,server_address,collection,command,status | Timer of mongodb commands | 
| mongodb_driver_commands_seconds_sum | cluster_id,server_address,collection,command,status | Timer of mongodb commands | 
Tracing¶
Currently, tracing is leveraged by Micrometer Tracing and OpenTelemetry in the Spring context. OpenTelemetry (OTEL) is a collection of standardized vendor-agnostic tools, APIs, and SDKs. It's a CNCF incubating project and is a merger of the OpenTracing and OpenCensus projects. OpenTracing is a vendor-neutral API for sending telemetry data over to an observability backend. It uses Micrometer for code instrumentation & provide tracing bridge to OpenTelemetry and OpenTelemetry for tools to collect and send telemetry data to the reporter/collector.
Default features are:
- Adds trace and span ids to the Slf4J MDC, so you can extract all the logs from a given trace or span in a log aggregator.
- Instruments common ingress and egress points from Spring applications (servlet filter, rest template, scheduled actions, message channels, feign client).
- The service name is derived from spring.application.name
- Generate and report OTLP traces via HTTP or gRPC. By default, it sends them to a OTLP compatible
  collector (e.g. Jaeger) on localhost (http port 4317, gRPC port 4318). Configure the location of
  the service using management.otlp.tracing.endpoint.
- See above for more common options.
- You can check all the possible values on OtlpTracingProperties and TracingProperties
Health Checks / Actuator¶
Configures the Spring Boot Actuator to be accessible on root path / at default management
port 8081.
The following endpoints are provided at the admin management endpoint:
- Liveness: http://{serviceURL}:{adminPort}/healthcheck/liveness
- Readiness: http://{serviceURL}:{adminPort}/healthcheck/readiness
The readiness group contains the following indicators:
- ReadinessStateHealthIndicator
- MongoHealthIndicator, if auto-configured.
- OpenPolicyAgentHealthIndicatorif OPA is enabled for authentication
To overwrite the defaults HealthIndicator of the readiness group, you can overwrite the property
source:
| 1 |  | 
Custom health indicators can be easily added to the application context:
| 1 2 3 4 5 6 7 |  | 
The custom health indicator will be available under /healthcheck/custom which is resolved by the
prefix of the HealthIndicator
implementing component.
Logging¶
The Spring Boot default logging is enabled.
Logs are printed to standard out.
ENABLE_JSON_LOGGING=true as environment variable or -Denable.json.logging=true as JVM parameter
enables output as JSON for structured logs used in log aggregation tools.
To enable JSON logging in application.(properties/yaml),
logging.config=classpath:org/sdase/commons/spring/boot/web/logging/logback-json.xml may be used.
The timestamp format of the json log can be configured with the environment variable 
LOG_JSON_TIMESTAMP_FORMAT, the default value is yyyy-MM-dd HH:mm:ss.SSS.
The timezone 
of the log timestamp can be changed using the TZ environment variable e.g. TZ=America/Belize.
This will change the timezone of the whole service. In general our recommendation is to make the 
timezone part of the timestamp format and let log aggregation tools handle the timezone conversion.
Correlation of Logs in Distributed Systems¶
To allow correlation of logs in distributed systems a Parent-Trace-Token header is added to a 
Kafka message if a Trace-Token is present in the MDC of the producer.
A Kafka RecordInterceptor is used to read out the header and add the Parent-Trace-Token to the MDC
of the consumer service.
This allows the consumer service to log the Parent-Trace-Token and the current Trace-Token
to trace the origin.
This only happens automatically if the used Listener is not a BatchListener
Metadata Context¶
If you want to make use of the data in the metadata context, you should read the dedicated documentation. If your service is required to support the metadata context but is not interested in the data, continue here:
Services that use the sda-spring-boot-commons:
- can access the current org.sdase.commons.spring.boot.metadata.context.MetadataContextin their implementation
- will automatically load the context from incoming HTTP requests into the thread, handling the
  request, if you register org.sdase.commons.spring.boot.web.metadata.MetadataContextConfiguration
- will automatically load the context from consumed Kafka messages into the thread handling the
  message and the error when handling the message fails when the consumer is configured with one of
  the provided org.sdase.commons.spring.boot.kafka.SdaKafkaConsumerConfiguration
- will automatically propagate the context to other services via HTTP when using
  a org.sdase.commons.spring.boot.web.client.PlatformClient:1 2 3 4 5 6 7 8 @PlatformClient( value = "name", url = "http://your-api-url" ) public interface ClientWithMetadataConfiguration { @GetMapping("/metadata-hello") Object getSomething(); }
- 
when using a FeignClient, that behaviour can be achieved by using the org.sdase.commons.spring.boot.web.metadata.MetadataContextClientConfigurationconfiguration.1 2 3 4 5 6 7 8 9 @FeignClient( value = "name", url = "http://your-api-url", configuration = { MetadataContextClientConfiguration.class } ) public interface ClientWithMetadataConfiguration { @GetMapping("/metadata-hello") Object getSomething(); }
- will automatically propagate the context in produced Kafka messages when the producer is created
  with org.sdase.commons.spring.boot.kafka.SdaKafkaProducerConfiguration
- are configurable by the property or environment variable METADATA_FIELDSto be aware of the metadata used in a specific environment
Services that interrupt a business process should persist the context from
MetadataContext.detachedCurrent() and restore it with MetadataContext.createContext(…) when the
process continues.
Interrupting a business process means that processing is stopped and continued later in a new thread
or even another instance of the service.
Most likely, this will happen when a business entity is stored based on a request and loaded later
for further processing by a scheduler or due to a new user interaction.
In this case, the DetachedMetadataContext must be persisted along with the entity and recreated
when the entity is loaded.
The DetachedMetadataContext can be defined as field in any MongoDB entity.
For services that handle requests or messages in parallel, the metadata context attributes will 
be automatically transferred to the new threads, if @Async is used.