skip to content

In Karate, what does `configure callSingleCache = { minutes: 15 }` change about `karate.callSingle()`, and what is the default?

level: seniorimportance: should knowfreq 34%

answer

  1. A second tier below the in-memory cache
  2. Default means memory only
  3. Freshness is a file timestamp
  4. Only plain data survives the trip
  5. Configure before you call

basics

~20 s

It 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 s

By 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 lines
javascript
function 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

for a junior

Remember the default: minutes is 0, so there is no file on disk and each run signs in once of its own.

for a middle

Describe the two tiers and the order of the checks, and note that only a JSON-like result reaches the file.

for a senior

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.

for a principal

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