Skip to content

Commit

Permalink
Merge pull request #38 from zazuko/xkey
Browse files Browse the repository at this point in the history
Add xkey support
  • Loading branch information
ludovicm67 authored May 29, 2024
2 parents 6d28f4b + 826b62c commit e7e3a6a
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 7 deletions.
14 changes: 14 additions & 0 deletions .changeset/twenty-experts-shave.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
"varnish-post": minor
---

Add xkey support in order to support tag-based invalidation.

The backend can now send a `xkey` header with a value that will be used to tag the cache entry.
This tag can be used to invalidate the cache entry by sending a `PURGE` request with the `xkey` header set to the same value like this:

```sh
curl -sL -X PURGE -H 'xkey: TAG_VALUE' http://varnish-endpoint/
```

Doing this will remove all cache entries that have the same tag value.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,9 @@ You can use following environment variables for configuration:
- `DISABLE_ERROR_CACHING_TTL`: time where requests should be directly sent to the backend after an error occured (default: `30s`)
- `CONFIG_FILE`: the name of the configuration file to use (default: `default.vcl`)
- `ENABLE_LOGS`: enable logs (default: `true`)

## Cache invalidation

You can invalidate the cache entry by sending the same request with the `PURGE` method.

If your backend is sending a `xkey` header, if you send a `PURGE` request with the same `xkey` header, it will invalidate all cache entries with the same tag.
8 changes: 7 additions & 1 deletion config/default.vcl
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ vcl 4.1;

import std;
import bodyaccess;
import xkey;

# Backend server that should be cached
backend default {
Expand Down Expand Up @@ -37,7 +38,12 @@ sub vcl_recv {

# Handle PURGE requests
if (req.method == "PURGE") {
return (purge);
if (req.http.xkey) {
set req.http.n-gone = xkey.purge(req.http.xkey);
return (synth(200, "Invalidated " + req.http.n-gone + " objects"));
} else {
return (purge);
}
}

# Caching POST requests by caching the request body
Expand Down
25 changes: 19 additions & 6 deletions test/app/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
import fastify from "fastify";
import fastifyFormbody from "@fastify/formbody";

// fetch values from environment variables
// Fetch values from environment variables
const port = process.env.SERVER_PORT || 8080;
const host = process.env.SERVER_HOST || "::";

// init fastify
// Init Fastify
const server = fastify({
logger: true,
});

server.register(fastifyFormbody);

// default route
// Default route
server.all("/", async () => ({
hello: "world",
time: Date.now(),
}));

// check particular error code
// Check particular error code
server.all<{
Params: {
code: number;
Expand All @@ -31,7 +31,20 @@ server.all<{
});
});

// say hello to someone
// Return a specific xkey header
server.all<{
Params: {
headerValue: string;
};
}>("/x-header/:headerValue", async (request, reply) => {
return reply.header("xkey", request.params.headerValue).send({
hello: "xkey header",
time: Date.now(),
value: request.params.headerValue,
});
});

// Say hello to someone
server.all<{
Params: {
name: string;
Expand All @@ -41,7 +54,7 @@ server.all<{
time: Date.now(),
}));

// start listening on specified host:port
// Start listening on specified host:port
(async () => {
try {
await server.listen({
Expand Down
54 changes: 54 additions & 0 deletions test/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,60 @@ if [ "${req2}" -ne "${req4}" ]; then
error "cache was purged"
fi

info "Check with xkey…"
# We cache a POST request (without xkey)
req0_1=$(curl -sL -X POST --data '{"foo": "bar"}' http://localhost:8081/x-header-test | jq .time)
# We cache a POST request
req1=$(curl -sL -X POST --data '{"foo": "bar"}' http://localhost:8081/x-header/test | jq .time)
# We cache another POST request
req2=$(curl -sL -X POST --data '{"foo": "foobar"}' http://localhost:8081/x-header/test | jq .time)
# Results should be different, because the payload is different
if [ "${req1}" -eq "${req2}" ]; then
error "should not be the same"
fi
if [ "${req1}" -eq "${req0_1}" ]; then
error "should not be the same"
fi
# Let's try to query the same endpoints with the same payload
req0_2=$(curl -sL -X POST --data '{"foo": "bar"}' http://localhost:8081/x-header-test | jq .time)
req3=$(curl -sL -X POST --data '{"foo": "bar"}' http://localhost:8081/x-header/test | jq .time)
req4=$(curl -sL -X POST --data '{"foo": "foobar"}' http://localhost:8081/x-header/test | jq .time)
req5=$(curl -sL -X POST --data '{"foo": "bar"}' http://localhost:8081/x-header/test2 | jq .time)
# Results should be cached
if [ "${req1}" -ne "${req3}" ]; then
error "should be the same"
fi
if [ "${req2}" -ne "${req4}" ]; then
error "should be the same"
fi
if [ "${req0_1}" -ne "${req0_2}" ]; then
error "should be the same"
fi
if [ "${req3}" -eq "${req5}" ]; then
error "should not be the same"
fi
# Let's try to purge the cache
curl -sL -X PURGE -H 'xkey: test' http://localhost:8081/x-header/anything >/dev/null
req0_3=$(curl -sL -X POST --data '{"foo": "bar"}' http://localhost:8081/x-header-test | jq .time)
req6=$(curl -sL -X POST --data '{"foo": "bar"}' http://localhost:8081/x-header/test | jq .time)
req7=$(curl -sL -X POST --data '{"foo": "foobar"}' http://localhost:8081/x-header/test | jq .time)
req8=$(curl -sL -X POST --data '{"foo": "bar"}' http://localhost:8081/x-header/test2 | jq .time)
if [ "${req6}" -eq "${req7}" ]; then
error "should not be the same"
fi
if [ "${req3}" -eq "${req6}" ]; then
error "should not be the same"
fi
if [ "${req4}" -eq "${req7}" ]; then
error "should not be the same"
fi
if [ "${req0_2}" -ne "${req0_3}" ]; then
error "should be the same"
fi
if [ "${req5}" -ne "${req8}" ]; then
error "should be the same"
fi

# If we are at this point, no test failed
info "All tests passed :)"
docker compose down
Expand Down

0 comments on commit e7e3a6a

Please sign in to comment.