In Karate, what does `configure callSingleCache = { minutes: 15 }` change about `karate.callSingle()`, and what is the default?
answer
- A second tier below the in-memory cache
- Default means memory only
- Freshness is a file timestamp
- Only plain data survives the trip
- Configure before you call
basics
~20 sIt spills the callSingle result to a file under the build directory and reuses it for fifteen minutes, so repeated local runs skip the sign-in entirely. The default is minutes 0, meaning memory only and one execution per run.
solid answer
~50 sBy default `karate.callSingle()` caches **in memory for one run** — `minutes` defaults to `0`, so the next run signs in again. Setting `minutes` makes Karate also write the result to a file under the build output directory, named after the path you passed; on a later run, if that file's last-modified time is inside the window, the result is read from disk and the target is **not executed at all**. That targets the development loop, where a token stays valid for a few minutes. Three constraints matter: only a JSON-like result is persisted, anything else is skipped with a warning; the `configure` must happen **before** the call it should affect, in practice the top of `karate-config.js`; and `dir` moves the file. Being a file with a clock on it, it belongs in dev, not CI.
code
javascript · 11 linesfunction fn() {
var env = karate.env || 'dev';
var config = { baseUrl: 'https://api.example.com' };
if (env == 'dev') {
// must come BEFORE the callSingle it should affect
karate.configure('callSingleCache', { minutes: 10, dir: 'target/karate-cache' });
}
var auth = karate.callSingle('classpath:get-token.feature', config);
config.authToken = auth.token;
return config;
}go deeper
Remember the default: minutes is 0, so there is no file on disk and each run signs in once of its own.
Describe the two tiers and the order of the checks, and note that only a JSON-like result reaches the file.
Treat it as a dev-loop switch: gate it on the environment, keep the window under the real credential lifetime, and know the log lines that show a hit or a stale file.
Weigh the saved seconds against a pipeline that can pass on a credential no run in it ever obtained, and set where that trade is allowed.
## What the setting adds `karate.callSingle()` always caches in memory for the duration of one run. `configure callSingleCache` adds a **second tier below that**: a file on disk that survives between runs. The configuration is a map with two recognised entries: - `minutes` — how long a written file stays usable. **Default `0`, which means no disk cache at all.** - `dir` — where the file is written. Defaults to a location under the build output directory (`target` or `build`, depending on the build tool). Both spellings reach the same setting: ```gherkin * configure callSingleCache = { minutes: 15, dir: 'target/karate-cache' } ``` ```javascript karate.configure('callSingleCache', { minutes: 15 }); ``` ## The flow on a call 1. Look in the in-memory cache for this run, keyed on the path string. Hit: return a copy, done. 2. Take the lock. Re-check memory in case another thread just filled it. 3. If `minutes` is greater than zero, derive a file name from the path and look for it. If the file exists **and its last-modified timestamp is inside the window**, parse it as JSON and use it — the target is never executed. 4. Otherwise execute the target, and if `minutes` is greater than zero write the result out as JSON. 5. Store in memory and return. Staleness is measured purely by the file's modification time against `now - minutes`. There is no token introspection, no expiry claim being read — Karate does not know what is in your token, only how old the file is. Set the window shorter than the real credential lifetime, not equal to it. ## The three constraints that catch people - **Only JSON-like results are written.** The disk tier serialises a map or list of plain data. A result carrying a JavaScript function or a Java object is not written; Karate logs a warning and the run proceeds with the in-memory cache only. This is the same "cache data, not behaviour" rule that governs `callonce`, made unavoidable by the fact that a file can hold only data. - **Order matters.** The minutes value is read at the moment `karate.callSingle()` runs. Configure it after the call and the first call has already gone to the network. In `karate-config.js` put the `karate.configure('callSingleCache', ...)` line above the `karate.callSingle(...)` line. - **The file name comes from the path key.** The same `?suffix` that splits the in-memory key also splits the file, so two variants of one feature get two files rather than fighting over one. ## Where it belongs, and where it does not This is a **developer-loop optimisation**. Enabling it means a run can pass using a credential obtained by a run you have since forgotten, which is precisely the confusion you do not want in CI: - In CI, leave it at the default `0`. A fresh sign-in per run is the honest behaviour, and a pipeline that reuses a cached token stops testing the sign-in path. - Locally, a window of a few minutes turns a fifteen-second start-up into an instant one when you are iterating on one feature. - Gate it on the environment rather than committing it on unconditionally — `karate-config.js` already has `karate.env` in hand, so the `configure` can sit inside a dev-only branch. ## Debugging it When behaviour looks impossible, the cache file is the first thing to look at. Karate logs each decision — a disk hit, a stale file with the timestamps, a miss that will create the file, a write, and a write skipped because the result was not JSON-like. Deleting the file forces a real execution; so does dropping `minutes` back to `0`. A file that keeps being ignored despite looking fresh is usually a path-key mismatch: the name is derived from the path string you passed, so changing `classpath:login.feature` to `login.feature` writes a different file. ## What it does not change The disk tier changes **where a result comes from**, never how many entries there are. `callSingle` still keys on the path string and still ignores the argument, so two calls to one file with different arguments still collide unless you add the `?suffix`. It also does not touch `callonce`, whose cache is per feature, in memory, and has no disk form at all.
- In Karate, what happens if a `karate.callSingle()` result contains a JavaScript function and `callSingleCache` is configured?The in-memory cache still works, but the disk write is skipped and a warning is logged, because only a JSON-like map or list can be serialised. This is the same guidance that applies to `callonce`: cache data, not behaviour. If you need a shared helper function, load it per scenario rather than trying to persist it.
- In Karate, how does `configure callSingleCache` decide that a cached file is stale?Purely by the file's last-modified timestamp against the configured window — if the file was modified more recently than `now` minus `minutes`, it is used; otherwise the target is executed and the file rewritten. Karate never inspects the content, so it has no idea when a token inside it actually expires. Keep the window comfortably shorter than the real credential lifetime.
saying these in an interview costs you the question
- Thinks disk caching is on by default
- Believes Karate reads the token's expiry to decide freshness
- Configures callSingleCache after the callSingle call
- Enables the disk cache in the CI pipeline
- Expects callonce to gain a disk cache from the same setting
- Assumes a function in the result is persisted too