Loading…
Loading…
Explains how the license enforcement state is evaluated, persisted, and used by the data plane, including configuration and troubleshooting.
The EnforcementStateMachine is a system component that determines the platform's license enforcement status. It centralizes the logic for evaluating the current license, applying a signed enforcement policy, and calculating a definitive EnforcementState (e.g., NORMAL, DEGRADED).
This component solves the problem of distributed license evaluation by creating a single, canonical state that other parts of the system can consume. It runs within the admin service, periodically refreshing the state and persisting it to the platform database. The runtime data plane reads this persisted state to enforce license restrictions without needing to perform its own evaluation.
This mechanism is distinct from the offline grace period handling for valid licenses that cannot currently reach the license authority. The two systems can apply their states independently, and consumers of the state are responsible for resolving them, typically by applying the more restrictive of the two.
The state machine's primary function is to execute a refresh cycle. This cycle is triggered on application startup and then on a recurring schedule. The refresh process performs the following sequence of operations:
EnforcementPolicy and LicenseState from the LicenseValidator.EnforcementEvaluator function to compute the final EnforcementState based on the policy, validity, and the duration of any invalidity.s2r_system_setting table in the database.This architecture decouples the complex evaluation logic from the high-performance data plane, which only needs to perform a simple database read.
flowchart TD
subgraph "Evaluation & Persistence (Admin API)"
A[Scheduler / Startup] --> B{Enforcement State Machine};
B -- "1. Reads" --> C(License & Enforcement Policy);
B -- "2. Determines validity" --> B;
B -- "3. Evaluates state" --> B;
B -- "4. Persists result" --> D[(Platform Database)];
end
subgraph "Enforcement (Data Plane)"
E[API Traffic] --> F{Runtime Enforcement Point};
F -- "Reads state" --> D;
endDuring each refresh cycle, the machine follows a clear logic to determine the EnforcementState.
The first step is to establish LicenseValidity.
licenseMode is MODE_LICENSED or if it is in a bootstrap() state, the license is considered VALID. The invalidSince timestamp is set to null, and any persisted value for specaria.unlicensed_since in the database is deleted.MODE_DISABLED), it is considered ABSENT. The machine then reads the specaria.unlicensed_since system setting.
invalidSince value.clock.instant()) is written to specaria.unlicensed_since and used as the invalidSince value. This marks the first moment the license was observed to be invalid.With the EnforcementPolicy, LicenseValidity, and invalidSince timestamp established, the machine calls the EnforcementEvaluator.evaluate() function. This function contains the core business logic to produce a final EnforcementState based on how long the license has been invalid according to the policy's defined thresholds.
If the new state is different from the previously cached state, an informational log is generated.
The computed state is persisted to the s2r_system_setting table as system-level rows under a dedicated platform tenant. This ensures that the data plane reads a single, authoritative state and that tenant-specific settings cannot interfere.
The following keys are used:
specaria.enforcement_mode: The mode from the enforcement policy (e.g., permissive, enforcing).specaria.enforcement_state: The final computed state (e.g., NORMAL, DEGRADED).specaria.unlicensed_since: The timestamp when the license was first found to be invalid.IMPORTANT
The EnforcementStateMachine is designed to be fail-safe. It will never throw an exception that could halt the admin service. Any database or other exception during the refresh cycle is caught, logged, and swallowed. In case of a failure, the machine preserves its last known valid state in the in-memory cache and continues operating.
The refresh interval for the state machine is configurable via the following system properties.
| Name | Type | Default | Required | Description |
|---|---|---|---|---|
s2r.specaria.enforcement-refresh-interval | Duration | PT5M | No | The ISO 8601 duration between scheduled enforcement state refreshes. |
s2r.specaria.enforcement-refresh-initial-delay | Duration | PT30S | No | The ISO 8601 duration to wait before the first scheduled refresh starts. |
The state machine writes the following key-value pairs to the s2r_system_setting table. These settings are the authoritative source for the runtime data plane.
| Key | Description |
|---|---|
specaria.enforcement_mode | The enforcement mode derived from the license policy's mode field. |
specaria.enforcement_state | The computed EnforcementState (e.g., NORMAL). This is the primary value consumed by the data plane. |
specaria.unlicensed_since | An ISO 8601 timestamp indicating when the license was first observed as invalid. This key is deleted when a valid license is detected. |
The EnforcementStateMachine component exposes methods for internal use and testing. These are not typically exposed over a public HTTP API.
EnforcementState currentState()Returns the current, in-memory cached EnforcementState. This state is updated by the scheduled refresh task. This allows other components within the admin service to access the current state without querying the database.
EnforcementState refresh()Manually triggers a full re-evaluation and persistence of the enforcement state. This method performs the same logic as the scheduled refresh. It is public to allow for direct invocation by other system components or for testing purposes.
EnforcementState.The component is designed to be resilient and provides detailed logging.
| Log Message | Level | Cause | Impact |
|---|---|---|---|
S2R-LIC enforcement state transition {}->{} (mode={}, days={}) | INFO | The computed enforcement state has changed from its previous value. | Normal operational behavior. The system will now operate under the new enforcement state. |
S2R-LIC enforcement refresh failed (keeping prior state {}): {} | WARN | An unexpected exception occurred during the refresh cycle (e.g., a database connection issue). | The state was not refreshed. The system continues to operate using the last known EnforcementState held in the in-memory cache. The operation will be retried on the next scheduled interval. |
S2R-LIC enforcement persist {} failed: {} | WARN | The component failed to write a setting (e.g., specaria.enforcement_state) to the s2r_system_setting table. | The database does not have the latest state. The data plane will continue to use the last successfully persisted state. The in-memory cache may be more current. |
S2R-LIC unlicensed_since unparseable ({}); reseeding | DEBUG | The value for the specaria.unlicensed_since key in the database was not a valid ISO 8601 timestamp. | The invalid timestamp is ignored, and a new timestamp (the current time) is written to the database. This may reset the "days unlicensed" counter. |
S2R-LIC readOrSetUnlicensedSince failed (using now): {} | DEBUG | A database error occurred while trying to read or write the specaria.unlicensed_since key. | The component falls back to using the current time as the start of the unlicensed period for this evaluation cycle, but the value is not persisted. |
S2R-LIC clear unlicensed_since failed: {} | DEBUG | A database error occurred while trying to delete the specaria.unlicensed_since key after a valid license was detected. | The stale specaria.unlicensed_since key may remain in the database, but it will not be used as long as the license remains valid. |
NOTE
The license JWT itself is never logged.
SpecariaGraceStateMachine, which manages enforcement when a still-valid license cannot be re-verified with the licensing authority (offline grace).