I built a Varnish VMOD that defines an object, which is instantiated in vcl_init
and is always kept in memory, and used in individual requests.
My configuration is split up in several VCL files, that get loaded from a "master" VCL depending on some request parameters.
The master VCL also instantiates the object in question, which I want to use in another VCL. The reason why I don't instantiate the object in the same VCL I use it in, is that I have another VCL that defines some ACL-restricted routes to update the object from a data source.
E.g. master.vcl
:
sub vcl_init {
new myobj = mymodule.myobject();
}
sub vcl_recv {
if (req.url ~ "^pub/") {
return (vcl (pub_vcl));
}
// Other switches...
}
pub.vcl
:
sub vcl_recv {
if myobj.mymethod() {
set req.http.x-bogus = "true";
}
}
But in this case, compilation fails because myobj
is undefined in pub.vcl
, which means it does not carry from master.vcl
.
I also thought about adding the test and header setting in master.vcl
before loading pub.vcl
, but that won't work because loading a VCL calls std.rollback(req)
which unsets all the request headers, which is the only variable accessible in vcl_recv
.
Is there a way to pass this state across VCL reloads?
Thanks.
You can't do this with objects directly as they are scoped by the VCL and can't "escape" it. As you've experienced, you need to load the labeled vcl first, so you also need to create the object in it.
But nothing prevents you from creating objects that reference a global variable so all objects have access to the same data.
Alternatively, you can use the Event
function to use a PRIV_VCL
(https://stackoverflow.com/a/60753085) also referencing a global pointer and avoid using objects completely. This is what is done here for example: https://github.com/varnish/varnish-modules/blob/master/src/vmod_vsthrottle.c#L345