Cached lookup¶
This private operation serializes access to the per-instance connection-string cache, returning a cached value when present and populating the cache from a retrieval when it is not. Failed retrievals are never cached.
| Field | Value |
|---|---|
| Operation ID | OP-DBC-06 |
| Trigger | Called internally by GetSqlServerConnection, GetPostgreSqlServerConnection, and GetOracleConnection |
| Inputs | connectionName (cache key), urlPath |
| Outputs | Connection string (or an exception propagated from retrieval) |
| Primary components | ConnectionClient.GetCachedConnectionString (private) |
| Entry point | src/SAIF.NetCore.DbConnectionClient/SAIF.NetCore.DBConnectionClient/SAIF.NetCore.DBConnectionClient/ConnectionClient.cs |
Steps¶
- Acquire
lock(_connections)(BR-DBC-06). The lock is instance-wide — shared across every cache key, not justconnectionName— so a slow or failing retrieval for one key blocks lookups for all other keys on the same instance until it completes*. - If the key is present in the cache, return the cached value immediately and release the lock — no HTTP call is made.
- If the key is absent, retrieve it with bounded retry before releasing the lock:
- Validate the backoff invariant (
RetrieveBackoffDelays.Length >= MaxRetrieveAttempts - 1); if it does not hold, throwInvalidOperationExceptionbefore any HTTP call (BR-DBC-07). - Loop up to
MaxRetrieveAttempts(4, by default) (BR-DBC-08): callHttpClient.GetAsync(urlPath)and read the per-attempt result. - On a successful, non-empty response: decode the legacy
ZSPECIALCHARtoken (BR-DBC-12), add the result to the cache, and return it. - On HTTP 401, 403, or 404: throw
DBClientExceptionimmediately, with no retry (BR-DBC-09). - On a 503 status or a non-null
ErrorException(network-level failure): treat it as transient (BR-DBC-10) — if attempts remain, wait the fixed backoff delay (2s, then 3s, then 5s) and retry; otherwise throwDBClientException. - On any other non-success status, or a successful-but-empty body: throw
DBClientExceptionimmediately (BR-DBC-11). - If retrieval throws for any reason, nothing is added to the cache — failures are never cached (BR-DBC-06).
-
Origin: Steps 3.1–3.5 are implemented in Retrieve with retry and executed on behalf of this operation, including the exact exception messages for each branch.
- Return the cached value and release the lock.
Process flow¶
flowchart TD
Start([GetCachedConnectionString called]) --> Lock[Acquire instance-wide lock on _connections]
Lock --> Present{Key present?}
Present -->|Yes| Return(["Return cached value, release lock"])
Present -->|No| Validate{Backoff config valid?}
Validate -->|No| ConfigErr(["Throw InvalidOperationException, release lock"])
Validate -->|Yes| Get[GetAsync urlPath]
Get --> Outcome{Outcome}
Outcome -->|Success, non-empty body| Decode["Decode ZSPECIALCHAR, add to cache"]
Decode --> Return
Outcome -->|401/403/404| FailFast(["Throw DBClientException, no retry, release lock"])
Outcome -->|503 or ErrorException| Remaining{Attempts remaining?}
Remaining -->|Yes| Delay["Delay 2s/3s/5s"] --> Get
Remaining -->|No| ThrowTransient(["Throw DBClientException, release lock"])
Outcome -->|Other non-success or empty body| ImmediateFail(["Throw DBClientException, release lock"])
Failure and edge-case behavior¶
- Because the lock is held across the entire retrieval attempt (including HTTP calls and backoff delays), a cold or failing lookup blocks every other caller of the same instance — including lookups for unrelated keys — for the duration of the retry loop*.
- A successfully retrieved value is cached for the life of the instance and never expires or is invalidated. Refreshing it requires replacing the instance — restarting the usual singleton-hosted process is the typical way to do this. Rotating the outbound NTLM service-account credential is distinct from this cache: it changes the identity presented on the next uncached request but does not clear any already-cached connection string*.
Related documentation¶
Note: Statements marked with
*were inferred from code structure, naming conventions, or contextual evidence where direct confirmation was not available in source artifacts.
Sources¶
src/SAIF.NetCore.DbConnectionClient/SAIF.NetCore.DBConnectionClient/SAIF.NetCore.DBConnectionClient/ConnectionClient.cs