-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathdefault.vcl
150 lines (126 loc) · 5.5 KB
/
default.vcl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# https://varnish-cache.org/docs/7.4/reference/vcl.html#versioning
vcl 4.1;
# Import std for duration comparisons & access to env vars
import std;
# Import vmod_dynamic to resolve backend hosts via DNS
import dynamic;
# Disable default backend, we are using dynamic backends **only**
backend default none;
# Force IPv6 backends **only**
acl ipv6_only { "::0"/0; }
probe changelog_health {
.url = "/health";
.interval = 5s;
.timeout = 2s;
.window = 10;
.threshold = 5;
}
# Setup a dynamic director
sub vcl_init {
# https://github.com/nigoroll/libvmod-dynamic/blob/3697d6f195fe077fe213918b7b67f5da4efdede2/src/tbl/list_prop.h
new changelog = dynamic.director(
ttl = 10s,
probe = changelog_health,
host_header = "changelog-2024-01-12.fly.dev",
first_byte_timeout = 5s,
connect_timeout = 5s,
between_bytes_timeout = 30s,
whitelist = ipv6_only
);
}
# NOTE: vcl_recv is called at the beginning of a request, after the complete
# request has been received and parsed. Its purpose is to decide whether or not
# to serve the request, how to do it, and, if applicable, which backend to use.
sub vcl_recv {
# https://varnish-cache.org/docs/7.4/users-guide/purging.html
if (req.method == "PURGE") {
return (purge);
}
# Implement a Varnish health-check
if (req.method == "GET" && req.url == "/varnish_health") {
return(synth(204));
}
# Make it clear what component we are health-checking
if (req.method == "GET" && req.url == "/backend_health") {
set req.url = "/health";
}
set req.backend_hint = changelog.backend("changelog-2024-01-12.internal", "4000");
}
# https://varnish-cache.org/docs/7.4/users-guide/vcl-grace.html
# https://docs.varnish-software.com/tutorials/object-lifetime/
# https://www.varnish-software.com/developers/tutorials/http-caching-basics/
# https://blog.markvincze.com/how-to-gracefully-fall-back-to-cache-on-5xx-responses-with-varnish/
sub vcl_backend_response {
# Objects within ttl are considered fresh.
set beresp.ttl = 60s;
# Objects within grace are considered stale.
# Serve stale content while refreshing in the background.
# 🤔 QUESTION: should we vary this based on backend health?
set beresp.grace = 24h;
if (beresp.status >= 500) {
# Don't cache a 5xx response
set beresp.uncacheable = true;
# If is_bgfetch is true, it means that we've found and returned the cached
# object to the client, and triggered an asynchoronus background update. In
# that case, since backend returned a 5xx, we have to abandon, otherwise
# the previously cached object would be erased from the cache (even if we
# set uncacheable to true).
if (bereq.is_bgfetch) {
return (abandon);
}
}
# 🤔 QUESTION: Should we configure beresp.keep?
}
# https://gist.github.com/leotsem/1246511/824cb9027a0a65d717c83e678850021dad84688d#file-default-vcl-pl
# https://varnish-cache.org/docs/7.4/reference/vcl-var.html#obj
sub vcl_deliver {
set resp.http.cache-status = "Edge";
# What is the remaining TTL for this object?
set resp.http.cache-status = resp.http.cache-status + "; ttl=" + obj.ttl;
# What is the max object staleness permitted?
set resp.http.cache-status = resp.http.cache-status + "; grace=" + obj.grace;
# Did the response come from Varnish or from the backend?
if (obj.hits > 0) {
set resp.http.cache-status = resp.http.cache-status + "; hit";
} else {
set resp.http.cache-status = resp.http.cache-status + "; miss";
}
# Is this object stale?
if (obj.hits > 0 && obj.ttl < std.duration(integer=0)) {
set resp.http.cache-status = resp.http.cache-status + "; stale";
}
# How many times has this response been served from Varnish?
set resp.http.cache-status = resp.http.cache-status + "; hits=" + obj.hits;
# Which region is serving this request?
set resp.http.cache-status = resp.http.cache-status + "; region=" + std.getenv("FLY_REGION");
}
# TODOS:
# - ✅ Run in debug mode (locally)
# - ✅ Connect directly to app - not Fly.io Proxy 🤦
# - ✅ Serve stale content + background refresh
# - QUESTION: Should the app control this via Surrogate-Control? Should we remove this header?
# - EXPLORE: varnishstat
# - EXPLORE: varnishtop
# - EXPLORE: varnishncsa -c -f '%m %u %h %{x-cache}o %{x-cache-hits}o'
# - ✅ Serve stale content on backend error
# - https://varnish-cache.org/docs/7.4/users-guide/vcl-grace.html#misbehaving-servers
# - ✅ Expose FLY_REGION=sjc env var as a custom header
# - https://github.com/varnish/docker-varnish/blob/45c6204864d46dbd9e18485c91f915f89f822859/old/debian/default.vcl#L35
# - ✅ If the backend gets restarted (e.g. new deploy), backend remains sick in Varnish
# - https://info.varnish-software.com/blog/two-minute-tech-tuesdays-backend-health
# - EXPLORE: varnishlog -g raw -i backend_health
# - EXPLORE: varnishadm backend.list
# - Add Feeds backend: /feed -> https://feeds.changelog.place/feed.xml
# - Send logs to Honeycomb.io
# - Store cache on disk? A pre-requisite for static backend
# - https://varnish-cache.org/docs/trunk/users-guide/storage-backends.html#file
#
# FOLLOW-UPs:
# - Run varnishncsa as a separate process (will need a supervisor + log drain)
# - https://info.varnish-software.com/blog/varnish-and-json-logging
# - How to cache purge across all varnish instances?
# - Implement If-Modified-Since? keep
#
# LINKS:
# - https://github.com/magento/magento2/blob/03621bbcd75cbac4ffa8266a51aa2606980f4830/app/code/Magento/PageCache/etc/varnish6.vcl
# - https://abhishekjakhotiya.medium.com/magento-internals-cache-purging-and-cache-tags-bf7772e60797