From 28b90c7b00dc48847b06d6463acb8f286292374d Mon Sep 17 00:00:00 2001 From: Rene Schallner Date: Mon, 3 Jul 2023 15:54:26 +0200 Subject: [PATCH] Endpoint example: /stop endpoint & leak detection --- examples/endpoint/main.zig | 79 +++++++++++++++++------------- examples/endpoint/stopendpoint.zig | 29 +++++++++++ 2 files changed, 74 insertions(+), 34 deletions(-) create mode 100644 examples/endpoint/stopendpoint.zig diff --git a/examples/endpoint/main.zig b/examples/endpoint/main.zig index a86a1f8..c387d94 100644 --- a/examples/endpoint/main.zig +++ b/examples/endpoint/main.zig @@ -1,6 +1,7 @@ const std = @import("std"); const zap = @import("zap"); const Endpoint = @import("endpoint.zig"); +const StopEndpoint = @import("stopendpoint.zig"); // this is just to demo that we can catch arbitrary slugs fn on_request(r: zap.SimpleRequest) void { @@ -17,44 +18,54 @@ pub fn main() !void { }){}; var allocator = gpa.allocator(); - // setup listener - var listener = zap.SimpleEndpointListener.init( - allocator, - .{ - .port = 3000, - .on_request = on_request, - .log = true, - .public_folder = "examples/endpoint/html", - .max_clients = 100000, - .max_body_size = 100 * 1024 * 1024, - }, - ); - defer listener.deinit(); + // we scope everything that can allocate within this block for leak detection + { + // setup listener + var listener = zap.SimpleEndpointListener.init( + allocator, + .{ + .port = 3000, + .on_request = on_request, + .log = true, + .public_folder = "examples/endpoint/html", + .max_clients = 100000, + .max_body_size = 100 * 1024 * 1024, + }, + ); + defer listener.deinit(); - var endpoint = Endpoint.init(allocator, "/users"); - defer endpoint.deinit(); + var endpoint = Endpoint.init(allocator, "/users"); + defer endpoint.deinit(); - // add endpoint - try listener.addEndpoint(endpoint.getUserEndpoint()); + var stopEp = StopEndpoint.init("/stop"); - // fake some users - var uid: usize = undefined; - uid = try endpoint.getUsers().addByName("renerocksai", null); - uid = try endpoint.getUsers().addByName("renerocksai", "your mom"); + // add endpoint + try listener.addEndpoint(endpoint.getUserEndpoint()); + try listener.addEndpoint(stopEp.getEndpoint()); - // listen - try listener.listen(); + // fake some users + var uid: usize = undefined; + uid = try endpoint.getUsers().addByName("renerocksai", null); + uid = try endpoint.getUsers().addByName("renerocksai", "your mom"); - std.debug.print("Listening on 0.0.0.0:3000\n", .{}); + // listen + try listener.listen(); - // and run - zap.start(.{ - .threads = 2000, - // IMPORTANT! It is crucial to only have a single worker for this example to work! - // Multiple workers would have multiple copies of the users hashmap. - // - // Since zap is quite fast, you can do A LOT with a single worker. - // Try it with `zig build run-endpoint -Drelease-fast` - .workers = 1, - }); + std.debug.print("Listening on 0.0.0.0:3000\n", .{}); + + // and run + zap.start(.{ + .threads = 2000, + // IMPORTANT! It is crucial to only have a single worker for this example to work! + // Multiple workers would have multiple copies of the users hashmap. + // + // Since zap is quite fast, you can do A LOT with a single worker. + // Try it with `zig build run-endpoint -Drelease-fast` + .workers = 1, + }); + } + + // show potential memory leaks when ZAP is shut down + const has_leaked = gpa.detectLeaks(); + std.log.debug("Has leaked: {}\n", .{has_leaked}); } diff --git a/examples/endpoint/stopendpoint.zig b/examples/endpoint/stopendpoint.zig new file mode 100644 index 0000000..2735074 --- /dev/null +++ b/examples/endpoint/stopendpoint.zig @@ -0,0 +1,29 @@ +const std = @import("std"); +const zap = @import("zap"); + +/// A simple endpoint listening on the /stop route that shuts down zap +/// the main thread usually continues at the instructions after the call to zap.start(). +pub const Self = @This(); + +endpoint: zap.SimpleEndpoint = undefined, + +pub fn init( + path: []const u8, +) Self { + return .{ + .endpoint = zap.SimpleEndpoint.init(.{ + .path = path, + .get = get, + }), + }; +} + +pub fn getEndpoint(self: *Self) *zap.SimpleEndpoint { + return &self.endpoint; +} + +fn get(e: *zap.SimpleEndpoint, r: zap.SimpleRequest) void { + _ = e; + _ = r; + zap.stop(); +}