Compare commits

..

5 Commits

Author SHA1 Message Date
abc26837a0
update README 2023-06-15 20:27:42 -07:00
6f1e37b391
complete name change 2023-06-15 20:26:49 -07:00
500847f571
remove unnecessary debug log 2023-06-15 20:21:04 -07:00
46d73f3983
PORT environment variable to adjust port number 2023-06-15 20:04:55 -07:00
f697e69d45
fix panic under heavy load 2023-06-15 20:03:51 -07:00
5 changed files with 41 additions and 17 deletions

View File

@ -26,13 +26,33 @@ library can be found in src/main-lib.zig.
Architecture Architecture
------------ ------------
TODO: This library assumes the use of Linux as a host. While the primary engine is not
tied to Linux, the file watcher module uses inotify and friends and will not
work outside that OS. PRs are welcome.
We assume Linux. The system is built with a pre-release version of zig, currently zig version
[0.11.0-dev.3312+ab37ab33c](https://github.com/marler8997/zig-unofficial-releases#0110-dev3312ab37ab33c-summary).
This version has web server in the standard library, so it is useful.
Built with zig 0.11.0-dev.3312+ab37ab33c (provide permalink). Explain lock to 0.11 when released. To achieve the lowest latency possible, this server loads dynamic libraries
using [dlopen(3)](https://linux.die.net/man/3/dlopen) based on a configuration
file in the current working directory called `proxy.ini`. An example of the
configuration is in this directory, and it is relatively simple string prefix
matching, again, for speed.
To achieve the lowest latency possible and eliminate the proliferation, The architecture of this server is setup On startup, a thread pool will be created. Request paths and header matching
is loaded from the configuration file, and file watches are initiated on all
libraries mentioned in the configuration file. Libraries are loaded on demand
when a request arrives that needs the library. When a library changes for a new
version, the file watcher will take note and unload the previous version.
Changes to the configuration file are not watched, relying instead on a HUP
signal to force a reload. At that point, all libraries ("executors") are
unloaded, and configuration is re-read.
As libraries are loaded directly into main process space, bugs in the libraries
can and will crash the engine. As such, some supervisory process (dockerd,
systemd, etc) should monitor and restart if necessary.
Security Security
-------- --------
@ -53,11 +73,13 @@ reported by the system (although thread count is limited to 4 threads when
compiled in debug mode). This can be controlled with the environment variable compiled in debug mode). This can be controlled with the environment variable
`SERVER_THREAD_COUNT`. `SERVER_THREAD_COUNT`.
Future plans include an environment variable for IP address and port to listen The port by default is 8069, although this can be set with the `PORT`
on, as well as the amount of pre-allocated memory for response data (currently environment variable. Future plans include an environment variable for IP
hardcoded to 1k/thread). Pre-allocated memory reduces the number of system address as well as the amount of pre-allocated memory for response data (currently
hardcoded to 8k/thread). Pre-allocated memory reduces the number of system
calls required for memory allocation, and pre-allocation/allocation statistics calls required for memory allocation, and pre-allocation/allocation statistics
per request are reported in the logs. per request are reported in the logs. The current pre-allocation provides
approximately 4k per request without requiring system calls.
Logs Logs
---- ----

View File

@ -16,7 +16,7 @@ pub fn build(b: *std.Build) void {
const optimize = b.standardOptimizeOption(.{}); const optimize = b.standardOptimizeOption(.{});
const exe = b.addExecutable(.{ const exe = b.addExecutable(.{
.name = "faas-proxy", .name = "flexilib",
// In this case the main source file is merely a path, however, in more // In this case the main source file is merely a path, however, in more
// complicated build scripts, this could be a generated file. // complicated build scripts, this could be a generated file.
.root_source_file = .{ .path = "src/main.zig" }, .root_source_file = .{ .path = "src/main.zig" },
@ -27,7 +27,7 @@ pub fn build(b: *std.Build) void {
exe.linkLibC(); exe.linkLibC();
const lib = b.addSharedLibrary(.{ const lib = b.addSharedLibrary(.{
.name = "faas-proxy-sample-lib", .name = "flexilib-sample-lib",
// In this case the main source file is merely a path, however, in more // In this case the main source file is merely a path, however, in more
// complicated build scripts, this could be a generated file. // complicated build scripts, this could be a generated file.
.root_source_file = .{ .path = "src/main-lib.zig" }, .root_source_file = .{ .path = "src/main-lib.zig" },
@ -37,7 +37,7 @@ pub fn build(b: *std.Build) void {
lib.linkLibC(); lib.linkLibC();
const interface_lib = b.addStaticLibrary(.{ const interface_lib = b.addStaticLibrary(.{
.name = "libfaasproxy", .name = "flexilib",
// In this case the main source file is merely a path, however, in more // In this case the main source file is merely a path, however, in more
// complicated build scripts, this could be a generated file. // complicated build scripts, this could be a generated file.
.root_source_file = .{ .path = "src/interface.zig" }, .root_source_file = .{ .path = "src/interface.zig" },

View File

@ -6,6 +6,6 @@
# Example of match based on an HTTP header. The key is space-delimited: # Example of match based on an HTTP header. The key is space-delimited:
# <http header key>: <header match prefix> <path match prefix> # <http header key>: <header match prefix> <path match prefix>
Host: iam / = zig-out/lib/libfaas-proxy-sample-lib.so Host: iam / = zig-out/lib/libflexilib-sample-lib.so
/c = zig-out/lib/libfaas-proxy-sample-lib-in-c.so /c = zig-out/lib/libflexilib-in-c.so
/ = zig-out/lib/libfaas-proxy-sample-lib.so / = zig-out/lib/libflexilib-sample-lib.so

View File

@ -28,7 +28,7 @@ pub const Request = extern struct {
}; };
// If the library is Zig, we can use these helpers // If the library is Zig, we can use these helpers
var allocator: ?*std.mem.Allocator = null; threadlocal var allocator: ?*std.mem.Allocator = null;
const log = std.log.scoped(.interface); const log = std.log.scoped(.interface);
@ -120,7 +120,6 @@ pub fn handleRequest(request: *Request, zigRequestHandler: ZigRequestHandler) ?*
return null; return null;
}; };
log.debug("response ptr: {*}", .{response.items.ptr});
// Marshall data back for handling by server // Marshall data back for handling by server
var rc = alloc.create(Response) catch { var rc = alloc.create(Response) catch {

View File

@ -362,7 +362,10 @@ pub fn main() !void {
var server = std.http.Server.init(allocator, .{ .reuse_address = true }); var server = std.http.Server.init(allocator, .{ .reuse_address = true });
defer server.deinit(); defer server.deinit();
const address = try std.net.Address.parseIp("0.0.0.0", PORT); const address = try std.net.Address.parseIp(
"0.0.0.0",
if (std.os.getenv("PORT")) |p| try std.fmt.parseInt(u16, p, 10) else PORT,
);
try server.listen(address); try server.listen(address);
const server_port = server.socket.listen_address.in.getPort(); const server_port = server.socket.listen_address.in.getPort();
log.info("listening on port: {d}", .{server_port}); log.info("listening on port: {d}", .{server_port});