I've released a significant update to the GmCapsule server. This version includes a couple of improvements I've been planning to implement for a while.
Hitherto, GmCapsule has relied on a pool of threads for handling incoming requests and generating responses. Multithreading in Python has a drawback, though: only one thread is allowed to execute Python code at any given time. This is acceptable for I/O-bound operations, like reading from and writing to network sockets, but if response generation requires a lot of computation, it was slowing down the overall performance of the server.
In v0.5, one can configure a number of additional helper processes (using Python `multiprocessing`) that run their own Python interpreters and can therefore generate responses concurrently. Complex applications like Bubble will benefit from this as operations like exporting an archive won't bog down other processing. The handler processes can be disabled if the previous behavior was sufficient.
The server now responds to a SIGHUP. It causes the configuration file to be reloaded and the worker threads/processes to be restarted. This means that extension modules can be modified and then reloaded without shutting down the server. It has been awkward updating Bubble when it requires shutting the server down completely for a minute.
Since static file serving, CGI, URL rewriting, and GitView are all extensions, one can now change their configuration on the fly as well.
The server socket and TLS configuration cannot be changed via a SIGHUP. That will still require a full restart.
To facilitate experimenting with Gemini-adjacent use cases, extension modules can now register handlers for custom URL schemes. The basic request structure is still expected to be a URI followed by CR LF and the request must be received over a TLS connection, but apart from that the received data can be freely interpreted. Client certificates are supported in custom handlers, too.
The changes in this version required modifying the extension module API.
The extension module `init` method receives a new `Context` object instead of the `Capsule`. The API is largely the same, but there are a few additions:
The `Identity` class now longer contains the original pyOpenSSL X.509 certificate and public key objects, because they are not compatible with `multiprocessing`. Instead, the DER serializations are stored in the `Identity` object. A request handler can construct runtime objects out of them if needed.
The original Gemtext version of this page can be accessed with a Gemini client: gemini://skyjake.fi/gemlog/2023-06_gmcapsule-0.5.gmi