> ## Documentation Index
> Fetch the complete documentation index at: https://docs.westyx.cloud/llms.txt
> Use this file to discover all available pages before exploring further.

# Go SDK - Caching Behaviour

> When does the Go SDK hit the network, snapshot atomicity, and ETag/304 support.

The SDK keeps every config / secret / flag in an **in-memory snapshot** that is replaced atomically as a whole on each sync. Reads never block on the network; only the periodic background goroutine does.

## When does the SDK hit the network

| Event                             | Result                                                                                            |
| --------------------------------- | ------------------------------------------------------------------------------------------------- |
| `NewClient(ctx, cfg)`             | **Blocking** full sync. The function only returns once the cache is populated (or with an error). |
| Read within the TTL window        | **No network** - served from the in-memory cache                                                  |
| Read after TTL has elapsed        | Stale cache returned **immediately**; one background goroutine is spawned to refresh              |
| Server returns `304 Not Modified` | TTL reset, no payload downloaded                                                                  |
| Multiple concurrent expirations   | Only **one** background sync runs at a time (atomic CAS guard)                                    |
| SSE event received                | Immediate full sync, regardless of TTL                                                            |
| SSE stream connected              | Effective TTL bumped to **60 s** as a safety net (the stream handles fresh updates)               |

## The atomic snapshot guarantee

The snapshot is replaced as one immutable struct value, behind a `sync.RWMutex`. Two goroutines reading concurrently either see the same old state or the same new state - never a mix.

```go theme={null}
val, ok := client.GetConfig("a")  // sees snapshot N
// ... another goroutine triggers a sync ...
val, ok := client.GetConfig("b")  // sees snapshot N+1 (or still N - but always consistent)
```

This means you can iterate `GetAllConfigs()` or `GetAllFlags()` without worrying about an entry being added or removed mid-loop. The returned map is also a defensive copy.

## ETag / 304

Every successful sync stores the server's `ETag`. The next sync sends `If-None-Match: <etag>`. If nothing has changed:

```
HTTP/1.1 304 Not Modified
```

...the SDK resets its `SyncedAt` timestamp and serves the existing snapshot. **No payload transferred.**

When the etag changes, the new payload replaces the cache atomically.

## Background sync errors

Background syncs **never return errors** to the caller. If the network call fails:

1. The error is logged via `Logger.Errorf(...)`
2. The existing cache continues to be served
3. The next read after the TTL elapses retries automatically

The application is never notified - the whole point is that a transient backend hiccup doesn't surface as a customer-facing error.

## Cache lifetime

The cache lives as long as the `*Client`. Cancelling the context passed to `NewClient` does NOT release the cache; it only affects the initial sync. A `*Client` typically lives for the entire process - share by passing a pointer, don't construct per-request.

## Diagnostics

| Method              | What it tells you                                                  |
| ------------------- | ------------------------------------------------------------------ |
| `client.SyncedAt()` | When was the last successful sync - useful for "last refreshed" UI |
| `client.KeyType()`  | `"sk"` or `"pk"` - confirms the SDK saw the right key prefix       |

When you wire up a `Logger`, the `Debugf` level emits one line per sync:

```
nexus: sync OK - configs=12 secrets=4 flags=7 key_type=sk
nexus: sync 304 Not Modified - cache retained
```

## Concurrency model

* **All reads are safe to call from any goroutine** - internally guarded by `sync.RWMutex`.
* **Background sync goroutine** - at most one at a time; spawned on TTL expiry.
* **SSE goroutine** - at most one, started when you call `go client.RunStream(ctx)`.

File-type secrets are materialised to `os.TempDir()` on every sync when the value changes. All temp files are removed when `client.Close()` is called.
