-- Leo's gemini proxy

-- Connecting to gemini.thegonz.net:1965...

-- Connected

-- Sending request

-- Meta line: 20 text/gemini

RREPLs and checkpointing

I'm still intermittently dreaming about wrapping line-based programs for use over gemini.

Previous post on the subject


Fantasy

The dream is to make this as simple for the server operator as CGI. You write something reading from stdin and writing to stdout, test it by just running it in a terminal, then hand it to your gemini server. Then it will be as if the server starts up an instance whenever anyone requests the corresponding url with a suitable client certificate set, with subsequent requests with the same certificate written to the stdin of the process, and anything written to stdout returned as responses to the requests.


Cryogenics

I say "as if", because there are problems with actually implementing it in this simplistic way. We never know when, if ever, the next request will come, so keeping a process running, using up RAM and potentially CPU indefinitely, isn't practical on any but the smallest scales. We would find we often have to kill old processes to free up resources, so the program will have to be robust against randomly being restarted -- and then we might as well just be using CGI directly.


Checkpointing might give a way around this. We still spin up a new instance of the program for each user as an actual process, but rather than keep it alive indefinitely we freeze it after each response, meaning that all state is written to disk, then thaw it back to a live process when the next request comes. This requires some deep kernel voodoo. A decade or so ago there was "cryopid" on linux which could do this, but kernel changes broke that long ago. Now there's "CRIU" which is maintained; it's used by docker, apparently, so probably will stay maintained for the foreseeable future.

CRIU


I've only recently managed to install it, and haven't experimented much. Sadly it seems to require root privileges, so some careful permissions management would be required to have it safely usable by a gemini server, which we certainly don't want to be running as root. It also requires some non-standard kernel options to be enabled, which could be annoying for potential users. And of course it's linux-only, and afaict there's nothing analagous for typical BSD systems. But in principle it seems like CRIU should do the job.


Reality

This still leaves us with some problems. Firstly, how do we decide that a process has finished responding and is ready to be frozen? One approach would be to require the process to give some signal that it's ready for the next input, but that's extra complication, and would allow a malfunctioning process to take arbitrary CPU time. I'm thinking instead that each request should grant the corresponding process a few seconds of CPU time: in that time anything written to stdout will be appended to the gemini response, then the response is closed and the process is frozen.


Secondly, frozen processes consume disk space, so we'll still have to kill them eventually. There's an obvious potential for DOS abuse. The space requirements can be significant -- whatever memory the process has mapped needs to be saved (though it can be compressed). So even without deliberate abuse, we can expect to hit limits eventually. I don't have any clever ideas for dealing with this...


So, that's as far as I've got. If anyone has any thoughts about the plausibility or desirability of this, or better ideas for how to go about it, please let me know.

-- Response ended

-- Page fetched on Sat Apr 27 04:55:29 2024