Loading…
Loading…
Describes the runtime component that detects applicative errors in SOAP test payloads by matching against a database of configurable error marker strings.
The RuntimeErrorMarkerLoader is a runtime service that detects applicative (business logic) errors within backend SOAP responses. Its primary function is to support the "Manual SOAP Test" feature (available at the /_test endpoint) by classifying a response payload as either a success or an applicative failure.
This component operates by searching a given response payload for specific, predefined "error marker" strings. These markers are configured by API publishers and stored in the s2r_learned_example_error_marker database table. The component can check for both global markers and markers specific to a single service.
It is designed to be a minimal, read-only component. To ensure that the Manual SOAP Test is not blocked by transient issues, the loader is fail-open. If it fails to load markers from the database, it logs the error at a DEBUG level and proceeds as if no applicative error was found, allowing the test call to complete.
To optimize performance, markers are loaded from the database and cached in memory with a 60-second Time-to-Live (TTL).
The component's logic involves loading markers from a database, caching them, and then matching them against a response payload. A key distinction is made between "deciding" markers, which can fail a test, and "advisory" markers, which are for informational purposes only.
Error markers are sourced from the s2r_learned_example_error_marker database table. The component executes a SQL query to fetch all rows where enabled = true.
select marker_text from s2r_learned_example_error_marker
where enabled = true
and ((?::uuid is null and service_id is null)
or service_id = ?::uuid)
order by marker_text
service_id is provided, it loads markers specific to that service.service_id is null, it loads global markers (where service_id in the table is NULL).Loaded markers are stored in an in-memory cache (ConcurrentHashMap) keyed by the serviceId. Global markers are cached under a dedicated key. Cache entries are considered stale and are reloaded from the database after 60,000 milliseconds (CACHE_TTL_MS).
When checking a payload, the component follows a precise matching sequence:
null or, after trimming whitespace, is shorter than 20 characters (MIN_PAYLOAD_LEN), the check is bypassed and no match is returned. This prevents false positives on short success messages.To avoid false positives, especially from common XML tags, markers are categorized into two types based on their scope (global vs. per-service) and format.
These are markers that, if found, will definitively classify the test response as an applicative error. The firstMatch method uses this set. The set of deciding markers for a given serviceId includes:
serviceId.<fault>).This exclusion prevents a global tag marker, which might appear in both success and error responses from some backends, from incorrectly failing tests for all services.
These are markers that suggest a potential issue but do not automatically fail the test. The firstAdvisoryMatch method uses this set. An advisory marker is a global marker that:
<status>).A match on an advisory marker should be surfaced to the API publisher for review, as it may indicate an error condition that warrants creating a more specific, deciding marker for that service.
The following diagram illustrates the logic flow when the firstMatch method is called to find a deciding error marker.
flowchart TD
subgraph "firstMatch(payload, serviceId)"
A[Start] --> B{Payload length < 20?};
B -->|Yes| C[Return null];
B -->|No| D[Get Deciding Markers for serviceId];
D --> E{Loop over each marker};
E -->|No more markers| C;
E -->|Next marker| F{Is marker ASCII?};
F -->|Yes| G{Payload (lowercased) contains marker (lowercased)?};
F -->|No| H{Payload (as-is) contains marker (as-is)?};
G -->|Yes| I[Return original marker string];
H -->|Yes| I;
G -->|No| E;
H -->|No| E;
I --> Z[End];
C --> Z;
end
subgraph "Get Deciding Markers"
style D fill:#f9f,stroke:#333,stroke-width:2px
D1[Load per-service markers from cache/DB] --> D4;
D2[Load global markers from cache/DB] --> D3[Filter out global markers shaped like <tag>];
D3 --> D4[Combine per-service and filtered global markers];
D4 --> D;
endConsider the following error markers configured in the s2r_learned_example_error_marker table:
marker_text | service_id | Notes |
|---|---|---|
Transaction failed | null | Global, non-tag marker |
<fault> | null | Global, XML-tag marker |
Error Code 99 | abc-123 | Per-service marker |
<fault> | abc-123 | Per-service marker (overrides global) |
abc-123firstMatch(payload, "abc-123")... <soap:body><fault>Error Code 99</fault></soap:body> ...Error Code 99 (per-service)<fault> (per-service)Transaction failed (global non-tag)"Error Code 99" or "<fault>" depending on which is found first. The test would be marked as failed.def-456firstMatch(payload, "def-456")... <soap:body><fault>Some other error</fault></soap:body> ...Transaction failed (global non-tag)<fault> marker is an XML tag and is excluded from the deciding set because it is not explicitly configured for service def-456.Transaction failed. The method returns null. The test would be marked as a success.def-456firstAdvisoryMatch(payload, "def-456")... <soap:body><fault>Some other error</fault></soap:body> ...<fault> (global XML-tag marker not configured for service def-456)<fault>. The method returns "<fault>". This result should be displayed to the user as a warning, suggesting they might want to configure this as a deciding error marker for their service.The component exposes the following public Java methods for use by the runtime.
| Method | Return Type | Description |
|---|---|---|
firstMatch(String payload, UUID serviceId) | String | Returns the first deciding error marker found in the payload. Returns null if no deciding marker matches, the payload is too short, or markers are unavailable. A non-null result indicates an applicative error. |
firstAdvisoryMatch(String payload, UUID serviceId) | String | Returns the first advisory (global, XML-tag) error marker found in the payload. Returns null if no advisory marker matches. A non-null result is for informational purposes only and does not indicate a definitive error. |
invalidate() | void | Clears the entire in-memory cache of error markers. The next call to firstMatch or firstAdvisoryMatch will force a reload from the database. This is primarily for testing but can be used to force a configuration refresh. |
The behavior of the RuntimeErrorMarkerLoader is controlled by data in the s2r_learned_example_error_marker table and by two internal constants.
s2r_learned_example_error_markerAPI publishers configure error markers by inserting or updating rows in this table.
| Column | Type | Required | Description |
|---|---|---|---|
marker_text | String | Yes | The literal string to search for in a response payload. Null or blank values are ignored. |
enabled | boolean | Yes | The loader only considers markers where this is true. |
service_id | UUID | No | The ID of the service this marker applies to. If null, the marker is global and applies to all services (subject to the deciding vs. advisory rules). |
These values are compiled into the component and are not configurable at runtime.
| Name | Value | Description |
|---|---|---|
MIN_PAYLOAD_LEN | 20 | Payloads shorter than this character length will not be checked for error markers. |
CACHE_TTL_MS | 60000 | The time-to-live for cached error markers, in milliseconds (60 seconds). |
The most common operational issue is a failure to connect to or query the database.
Fail-Open Behavior
RuntimeException occurs during the database load operation.DEBUG level but does not throw an exception.DEBUG messages matching the following format:
error-marker DB load failed (key=...); treating as no applicative error: ...
s2r_learned_example_error_marker table. This component is a read-only client of that data.