Skip to main content

Cache Admin API

The Cache Admin API purges and seeds tiles in the cache over HTTP. A request does the same as shigola cache purge or shigola cache seed, so a service that knows which part of the map changed, such as retiler after an OSM update, can refresh those tiles without running the CLI.

It runs on its own port, separate from the tile port, and is off by default. Keep that port off any gateway or ingress that is open to clients: it is meant for in-cluster callers only.

Enabling it​

[webserver]
port = ":8080"

[webserver.admin]
port = ":9090"
token = "${SHIGOLA_ADMIN_TOKEN}"
ParamRequiredDefaultDescription
portNoThe port the API listens on. Setting it turns the API on. It must differ from the tile port.
tokenNoA secret that requests to /cache/* must send as Authorization: Bearer <token>.
max_tiles_per_requestNo10000The most cache keys one request may touch. See Limits.
max_concurrent_requestsNo4The most requests worked on at once.
request_timeout_msNo60000How long a request may run before its remaining work is cancelled.

The admin token​

When token is set, a request without Authorization: Bearer <token>, or with a different token, gets 401 and touches nothing. Take the token from the environment, as above, rather than writing it into the config file.

The token is optional, because the port should be unreachable from outside anyway. Without one, Shigola logs a loud WARN at startup naming the port, so an unprotected API does not go unnoticed.

Exploring it​

The admin port serves its own description:

  • GET /docs: Swagger UI, for reading the API and trying requests. Use Authorize to enter the token. It is served from the binary, so it works without internet access.
  • GET /openapi.json: the OpenAPI 3 document behind it.

Neither needs the token. Only the /cache/* routes do.

POST /cache/purge​

Purges the tiles covering an area at a range of zooms, from every tile matrix set each targeted map serves, or only from those named in tileMatrixSets.

curl -X POST http://localhost:9090/cache/purge \
-H "Authorization: Bearer $SHIGOLA_ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"bounds": [34.75, 32.05, 34.80, 32.10],
"zoomRange": { "min": 10, "max": 14 },
"targets": [ { "map": "osm" } ]
}'
FieldRequiredDescription
boundsOne of bounds or tilesThe area as [west, south, east, north] in lng/lat. A box with west greater than east crosses the antimeridian.
tilesOne of bounds or tilesThe area as a list of z/x/y tile names in sourceTileMatrixSet. Each tile stands for the ground it covers.
sourceTileMatrixSetWith tilesThe tile matrix set the tiles names belong to, by id. It does not choose which sets are worked on; tileMatrixSets does.
tileMatrixSetsNoWork on only these tile matrix sets, by id, as --tile-matrix-set does for the CLI. Every targeted map must serve each one, or the request gets 400. Omitted, every set each map serves.
zoomRangeYes{ "min": …, "max": … }, inclusive.
targetsYesThe maps to purge, each { "map": "…", "layers": [ … ] }. A request without targets gets 400.

Every tile matrix set a map serves is purged unless tileMatrixSets narrows it. The area is tiled in each of the map's tile matrix sets at the same zoom numbers, so a map served in both WebMercatorQuad and WorldCRS84Quad loses the covering tiles from both. Purging only some sets leaves the others serving their cached copies of the same data. Tiles that only touch the area's edge are not included. Latitudes outside a set's extent are clipped, so WebMercatorQuad covers up to ±85.05°.

Layers. With no layers, a target clears its whole-map tile and every layer's tile. Naming layers clears those layers' tiles and the whole-map tile, which contains them too. Other layers are left alone. This is the same rule as --layers.

A purge clears every tier of a layered cache, but a file tier only on the replica that handled the request. Give file tiers a short ttl so the other replicas let go of the purged tile too. Shigola warns at startup about any that have none. See Purging across replicas.

POST /cache/seed​

Renders the whole-map tiles covering an area and writes them to the cache, in every tile matrix set each targeted map serves, or only those named in tileMatrixSets. The body is the same as a purge's, plus two fields that mean what the CLI's flags mean:

FieldRequiredDescription
overwriteNotrue re-renders tiles already cached. Without it they are skipped and counted in skipped. With a layered cache it also purges the tiers not written, so the hot tier stops serving the old tile.
tiersNoFor a layered cache, the comma-separated tiers to write, or "all". Omitted, only the last tier in read order is written, as with --cache-tiers.
curl -X POST http://localhost:9090/cache/seed \
-H "Authorization: Bearer $SHIGOLA_ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"bounds": [34.75, 32.05, 34.80, 32.10],
"zoomRange": { "min": 10, "max": 14 },
"targets": [ { "map": "osm" } ],
"overwrite": true
}'

The response reports seeded where a purge reports purged.

Seeding is whole-map only. A target naming layers gets 422: a layer's tiles are cached as they are requested. overwrite is seed only, and a purge given it gets 400. A purge accepts tiers as the CLI's purge does, and gets 400 for a tier that does not exist, but it clears every tier regardless.

Seeding renders on the pod that serves tiles. Each tile is a database query, so a large seed competes with users for the database and the CPU. Keep seeds small, or run large ones with the CLI.

Limits​

The API runs on the same pods that serve tiles, so it refuses work that could tie them up:

  • Size. A request may touch at most max_tiles_per_request cache keys, counted across every tile matrix set, zoom and layer it covers. A purge of a map with two layers counts three keys per tile: the whole-map tile and each layer's. A larger request gets 422 and touches nothing. Narrow it, or use the shigola cache CLI, which has no such limit.
  • Concurrency. At most max_concurrent_requests run at once. Another request gets 429 with a Retry-After header and touches nothing.
  • Duration. A request still running after request_timeout_ms has its remaining work cancelled and gets 503 with the counts so far. A client that disconnects cancels its request the same way. Repeat the purge to finish it: purging a tile twice is harmless.

Response​

The request runs to completion before the response is sent.

{ "purged": 42, "skipped": 0, "failed": 0, "durationMs": 18 }

Counts are per map tile: one tile purged from two maps counts twice.

A request refused before any tile is touched (400, 401, 422, 429) gets only { "error": "…" }, with no counts.

StatusMeaning
200Every tile was purged.
400The request was malformed or its body was over 1 MiB, or named a map, layer, tile or tile matrix set that does not exist. error says which. Nothing was purged.
401A token is configured and the request did not send it. Nothing was purged.
422The request covers more than max_tiles_per_request, or is a seed naming layers. Nothing was touched.
429max_concurrent_requests are already running. Retry after Retry-After seconds. Nothing was purged.
500Some tiles could not be purged, usually because a cache backend failed. Every tile was still attempted: failed counts the ones that failed and error gives the first failure. Purging the same area again is safe.
503The request timed out. The body holds the counts so far. Purging the same area again is safe.