Class ApiKeyLastUsedService

java.lang.Object
com.axelor.auth.ApiKeyLastUsedService

public class ApiKeyLastUsedService extends Object
Service keeping track of when API keys are used.

API key authentication is stateless: it happens on every single request. Writing the lastUsedAt of the API key each time turns a read-only workload into one UPDATE plus one commit per request and invalidates the cache regions of UserToken just as often.

The timestamp is therefore only refreshed once per INTERVAL, making it accurate to within that interval. On top of that, a lease of LEASE_TIMEOUT keeps concurrent requests sharing an API key from all refreshing it at once.

  • Field Details

    • INTERVAL

      protected static final Duration INTERVAL
      Duration during which lastUsedAt is not refreshed again.
    • LEASE_TIMEOUT

      protected static final Duration LEASE_TIMEOUT
      Duration of the lease acquired to refresh lastUsedAt.
  • Constructor Details

    • ApiKeyLastUsedService

      public ApiKeyLastUsedService()
  • Method Details

    • setLastUsed

      public void setLastUsed(UserToken userToken)
      Refreshes the lastUsedAt of the given token, unless it has been refreshed recently enough.
      Parameters:
      userToken - the token being used
    • isOutdated

      protected boolean isOutdated(UserToken userToken, LocalDateTime now)
      Whether the lastUsedAt of the given token is outdated enough to be written again.
      Parameters:
      userToken - the token being used
      now - the current time
      Returns:
      true if lastUsedAt is older than the interval
    • tryAcquireLease

      protected boolean tryAcquireLease(UserToken userToken)
      Tries to acquire the lease allowing to refresh the lastUsedAt of the given token.

      Once the interval has elapsed, concurrent requests using the same key all see the same outdated value. Only the one acquiring the lease refreshes it, the others move on: they would otherwise queue on the very same row. The lease is not released once the refresh is done, it expires after LEASE_TIMEOUT, which also covers the requests that read lastUsedAt before the refresh but reach this point after it.

      The lease is always acquired, so that lastUsedAt is never refreshed more than once per LEASE_TIMEOUT. It is the last guard against a burst of requests hammering the very same row.

      Parameters:
      userToken - the token being used
      Returns:
      true if the lease was acquired
    • update

      protected void update(UserToken userToken, LocalDateTime lastUsedAt)
      Writes the lastUsedAt of the given token.

      This performs a non-versioned update: version, updatedOn and updatedBy are intentionally left untouched, as using an API key is not a modification of the token. Keeping version out of it also means concurrent requests sharing a key can no longer make each other fail with an optimistic lock error.

      Parameters:
      userToken - the token being used
      lastUsedAt - the value to write