mojodna / tessera

A tilelive-based tile server.
BSD 2-Clause "Simplified" License
324 stars 80 forks source link

Need a way to handle cache control headers for rasters rendered from overzoomed vectors #62

Closed JesseCrocker closed 8 years ago

JesseCrocker commented 8 years ago

What I'm doing: I've got a set of vector tiles that goes to zoom 14, and render rasters using tilelive-tmstyle up to zoom 20. Im using a "Surrogate-Keys" header to enable invalidating rasters from a CDN when one of the vector tiles is updated, using https://github.com/trailbehind/tilelive-expire-fastly/

Example entry from my config.json:

    "/feet-raster": {
        "source": "tmstyle:///home/ubuntu/tm2-projects-private/gaia_topo_feet.tm2/",
        "headers": {
            "Cache-Control": "public,max-age=86400",
            "Surrogate-Control": "max-age=31536000",
            "Surrogate-Keys": "{{#tile}}z{{zoom}}/x{{x}}/y{{y}}{{/tile}}"
        }

The problem: The raster tile 16/1/2 generates a header of surrogate-keys: z16/x1/y2, but this tile is rendered from the vector tile 14/1/1. When the vector tile 14/1/1 is rendered I invalidate z/14/x1/y1, which properly invalidates the z14 rasters, but not the z15-z20 rasters.

I see 2 possible ways to fix this:

  1. When the z14 vector tile is rendered don't just invalidate 1 key, invalidate keys for all the children of that tile down to z20.
  2. Add new syntax to the header templating to make it so tile 16/1/2 can generate the header surrogate-keys: z14/x1/y1.

I think solution number 1 is clearly a bad idea, and 2 is the correct way to go. Im planning on implementing 2, but if anyone has a better idea of how to handle this i'd be glad to hear it.

The implementation would involve adding an additional context(?) to the params that get passed to populateHeaders in getTile, something like tileMaxZ that at zooms less than or equal to the max contains the same values as tile, but at zooms greater than the max contains the z/x/y values for the tiles parent tile at the max zoom. What this max zoom is would be configurable in the config.json, and the additional values would only be calculated if it was set.

mojodna commented 8 years ago

Hmm. From an operational point of view, I'd agree that (2) is correct.

I was originally thinking that the solution would involve specifically extracting appropriate context from tilelive-vector (or tilelive-merge or ...), but I think you're right that it can be determined at getTile time. It seems like it involves additional API (or uncovering existing methods / properties that could be formalized).

maxzoom is a TileJSON property, so if the max maxzoom is obtained from the source's source (a vector tile source in the case of tilelive-vector via source._backend.getInfo()), that could be used to seed the surrogate key.

tilelive-merge (and tilelive-blend, despite not supporting overzooming yet) have multiple sources, so that's something to take into account...

Good problem.