Loading…
Loading…
Documents the Generic Traffic Learning Service, a scheduled curator that processes non-F5 traffic logs to generate learned API examples and discovery
The Generic Traffic Learning Service is a scheduled background process that curates API traffic from generic, non-F5 sources. It functions as a multi-source learned-example curator, mirroring the capabilities of the F5-specific traffic learning service but adapted for different log formats.
The primary problem this service solves is the ingestion and processing of API traffic logs that are bulk-inserted into a database, rather than being streamed via individual HTTP requests. The s2r-generic-ingest service populates the s2r_generic_request_log table, and this service polls that table for new records to process.
The service's main responsibilities are:
s2r_generic_learned_example table.s2r_observed_traffic_hourly table for discovery and analytics.s2r_observed_topology table.s2r_generic_learned_field_value to aid in API onboarding and data encoding analysis.This service operates independently of F5-related traffic processing to ensure that a failure in one does not impact the other.
The service runs periodically, processing new traffic logs in batches. Its operation is designed to be robust, idempotent, and safe for concurrent execution in a multi-instance environment.
s2r.generic-learning.scheduler.delay-ms), with an initial startup delay (s2r.generic-learning.scheduler.initial-delay-ms).pg_try_advisory_xact_lock) at the start of each run. The lock is transaction-scoped, ensuring it is automatically released upon commit or rollback, which prevents orphaned locks. If the lock cannot be acquired, the tick is skipped.The service uses an in-memory watermark (lastProcessedId) to track its progress through the s2r_generic_request_log table.
s2r_generic_learned_example table for the highest generic_request_log_id it has already processed. This makes the watermark durable across restarts, preventing the service from re-processing the entire log history from the beginning.INSERT ... ON CONFLICT logic in the database prevents duplicate examples and ensures that counters like seen_count are not incorrectly inflated. A special WHERE clause in the UPDATE statement checks the source log ID to make re-processing a no-op.Each processing tick follows a series of steps to fetch, process, and persist traffic data.
flowchart TD
subgraph Service Tick
A[Scheduler Triggers] --> B{Acquire Advisory Lock?}
B -- Yes --> C[Fetch Batch from s2r_generic_request_log]
B -- No --> D[Skip Tick]
C --> E{For each row in batch}
E -- row --> F[Parse & Identify]
F --> G[Update Discovery Tables<br>(s2r_observed_traffic_hourly, s2r_observed_topology)]
G --> H{Is Traffic Successful?}
H -- Yes --> I[Upsert to s2r_generic_learned_example]
I --> J[Enforce Example Cap]
J --> K[Learn Leaf Fields from SOAP]
K --> L[End Row Processing]
H -- No --> L
L -- next row --> E
E -- end of batch --> M{Commit Transaction}
M -- Success --> N[Advance Watermark]
M -- Failure --> O[Rollback & Log Error<br>(Watermark Unchanged)]
ends2r_generic_request_log table for rows with an id greater than the current watermark, up to a limit of BATCH_SIZE. It includes a COMMIT_LAG_SECONDS delay to avoid processing rows from transactions that may not have committed yet.SOAP, XML, JSON, or NONE.service_backend_key from the backend_uri. If the URI only contains a path, it creates a synthetic key based on front_virtual_server or frontend_uri.Authorization, Cookie) with ***.operationName from the payload (e.g., SOAP operation name, XML root element, or request path).service_id by matching the backend URI against onboarded service profiles.s2r_observed_traffic_hourly: Increments hit counters for the corresponding hour, service, and infrastructure components.s2r_observed_topology: Records the observed link between frontend and backend virtual servers.INSERT ... ON CONFLICT statement is executed to save the transaction to s2r_generic_learned_example. If an example with the same signature already exists, its seen_count is incremented.LEARNED_EXAMPLE_CAP) on the number of examples stored per service and operation, deleting the oldest ones to stay within the limit.s2r_generic_learned_field_value, which collects a sample set of observed values for each field.The service fetches new log entries using a query that respects the watermark and a commit safety lag.
select id, event_id, gateway_type, connector_instance_id, event_timestamp,
frontend_uri, backend_uri,
front_virtual_server, back_virtual_server,
client_ip::text as client_ip_text,
http_method, http_status,
request_payload, response_payload,
request_headers, response_headers
from s2r_generic_request_log
where id > ?
and received_at <= now() - make_interval(secs => ?)
order by id asc
limit ?
The parameters correspond to the current lastProcessedId watermark, COMMIT_LAG_SECONDS, and BATCH_SIZE.
The service's scheduler can be configured via the following application properties.
| Name | Type | Default | Required | Description |
|---|---|---|---|---|
s2r.generic-learning.scheduler.enabled | Boolean | true | No | Enables or disables the scheduled execution of the service. Set to false in test environments or to disable the feature. |
s2r.generic-learning.scheduler.delay-ms | String | "60000" | No | The fixed delay in milliseconds between the completion of one execution and the start of the next. |
s2r.generic-learning.scheduler.initial-delay-ms | String | "45000" | No | The initial delay in milliseconds after application startup before the first execution begins. |
The service operates with several hardcoded limits that define its behavior. These are not externally configurable.
| Constant | Value | Description |
|---|---|---|
BATCH_SIZE | 500 | The maximum number of rows to process from s2r_generic_request_log in a single tick. This caps database pressure. |
LEARNED_EXAMPLE_CAP | 5 | The maximum number of learned examples to retain per unique combination of service_backend_key and soap_operation_name. Older examples are evicted. |
FIELD_SAMPLE_CAP | 20 | The maximum number of distinct value samples to retain for each learned leaf field in s2r_generic_learned_field_value. |
FIELD_LEAF_CAP | 256 | The maximum number of leaf fields to extract from a single SOAP request or response body. |
COMMIT_LAG_SECONDS | 5 | The safety lag in seconds. The service only processes log rows that were received at least this many seconds in the past to avoid race conditions with concurrent ingest transactions. |
MIN_SOAP_PAYLOAD_LEN | 20 | The minimum payload length required to attempt SOAP parsing. Payloads smaller than this are skipped. |
The service exposes public methods primarily for scheduling and testability.
runScheduled()This is the main entrypoint invoked by the Spring scheduler. It wraps the core logic in a re-entrancy guard and top-level exception handling. It takes no parameters and has no return value.
runOnce()This method executes a single pass of the curator logic: it attempts to acquire the lock, fetches and processes one batch of rows, and advances the watermark. It is public for testability and manual invocation.
int – The number of log rows scanned in the batch. This is not the same as the number of examples inserted, as many rows may be skipped.The service logs its state and any issues encountered. The following log messages can help diagnose operational problems.
NOTE
Most "skipped" or "failed" messages for individual rows are logged at the DEBUG level. To see them, you may need to adjust the logging configuration for the com.specaria.s2r.worker.service.GenericTrafficLearningService class.
| Log Message | Meaning |
|---|---|
Generic learning curator skipped: previous tick still running | The previous processing run took longer than the configured delay-ms. The current tick is skipped to prevent overlap. This may indicate high load or slow database performance. |
Generic learning curator: another instance holds the xact lock; skipping tick | Another service instance in the cluster holds the advisory lock. This is normal and expected in a multi-instance deployment. |
Generic learning curator tick failed: {message} | An unexpected RuntimeException occurred during a scheduled run. The exception details are logged. The tick is aborted. |
Generic learning curator: transaction did not commit cleanly; watermark unchanged: {message} | The database transaction for a batch failed to commit. The watermark is not advanced, and the entire batch will be retried on the next tick. |
Generic learning curator: DB write failed on row {id}; aborting batch (watermark stays at {watermark}): {message} | A database write (INSERT, UPDATE, or DELETE) failed for a specific row. The entire batch is rolled back, and the watermark is not advanced. The failing row will be retried on the next tick. |
Generic learning curator: row {id} skipped (non-DB): {message} | A row was skipped due to an issue with its content (e.g., malformed payload, missing required fields). The watermark will be advanced past this row, and it will not be retried. |
Generic learning curator: watermark lazy-init failed; defaulting to 0: {message} | The service could not query s2r_generic_learned_example on startup to determine the last processed log ID. It will start processing from the beginning of s2r_generic_request_log. This is safe due to idempotency but may cause a temporary increase in load. |
s2r-generic-ingest) responsible for receiving logs from various sources and populating the s2r_generic_request_log table that this service reads from.