https://github.com/guzba/mummy Skip to content Toggle navigation Sign up * Product + Actions Automate any workflow + Packages Host and manage packages + Security Find and fix vulnerabilities + Codespaces Instant dev environments + Copilot Write better code with AI + Code review Manage code changes + Issues Plan and track work + Discussions Collaborate outside of code + Explore + All features + Documentation + GitHub Skills + Blog * Solutions + For + Enterprise + Teams + Startups + Education + By Solution + CI/CD & Automation + DevOps + DevSecOps + Case Studies + Customer Stories + Resources * Open Source + GitHub Sponsors Fund open source developers + The ReadME Project GitHub community articles + Repositories + Topics + Trending + Collections * Pricing [ ] * # In this repository All GitHub | Jump to | * No suggested jump to results * # In this repository All GitHub | Jump to | * # In this user All GitHub | Jump to | * # In this repository All GitHub | Jump to | Sign in Sign up {{ message }} guzba / mummy Public generated from treeform/nimtemplate * Notifications * Fork 6 * Star 123 An HTTP and WebSocket server for Nim that returns to the ancient ways of threads. License MIT license 123 stars 6 forks Star Notifications * Code * Issues 0 * Pull requests 1 * Actions * Projects 0 * Security * Insights More * Code * Issues * Pull requests * Actions * Projects * Security * Insights guzba/mummy This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository. master Switch branches/tags [ ] Branches Tags Could not load branches Nothing to show {{ refName }} default View all branches Could not load tags Nothing to show {{ refName }} default View all tags Name already in use A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch? Cancel Create 6 branches 6 tags Code * Local * Codespaces * Clone HTTPS GitHub CLI [https://github.com/g] Use Git or checkout with SVN using the web URL. [gh repo clone guzba/] Work fast with our official CLI. Learn more. * Open with GitHub Desktop * Download ZIP Sign In Required Please sign in to use Codespaces. Launching GitHub Desktop If nothing happens, download GitHub Desktop and try again. Launching GitHub Desktop If nothing happens, download GitHub Desktop and try again. Launching Xcode If nothing happens, download Xcode and try again. Launching Visual Studio Code Your codespace will open once ready. There was a problem preparing your codespace, please try again. Latest commit @guzba guzba Merge pull request #25 from guzba/ryan ... eff35e2 Dec 29, 2022 Merge pull request #25 from guzba/ryan waitUntilReady eff35e2 Git stats * 239 commits Files Permalink Failed to load latest commit information. Type Name Latest commit message Commit time .github/workflows test ensuring responses go to correct requesters Dec 1, 2022 docs add line about name Dec 2, 2022 examples add database example Dec 12, 2022 src waitUntilReady Dec 29, 2022 tests waitUntilReady Dec 29, 2022 .gitignore add database example Dec 12, 2022 LICENSE f Nov 17, 2022 README.md add sites using mummy section Dec 24, 2022 config.nims orc acyclic Nov 22, 2022 mummy.nimble 0.2.4 Dec 29, 2022 View code [ ] Mummy Sites using Mummy How is Mummy different? Why use Mummy instead of async? Why prioritize WebSockets? What is Mummy not great for? Example HTTP server Example WebSocket server Performance Benchmarks Mummy AsyncHttpServer HttpBeast Jester Prologue NodeJS Go Testing README.md Mummy nimble install mummy Github Actions API reference Mummy is a multi-threaded HTTP 1.1 and WebSocket server written entirely in Nim. A return to the ancient ways of threads. Mummy has been written specifically to maximize the performance of your server hardware without compromising on programmer happiness. * Supports HTTP keep-alive and gzip response compression automatically. * Built-in first-class WebSocket support. * Multiplexed socket IO without the {.async.} price. [?][?] Mummy is brand new so please exercise reasonable caution! Mummy requires --threads:on and --mm:orc or --mm:arc. The Mummy name refers to historical Egypt stuff. Sites using Mummy * NimDocs.com - view the source code here How is Mummy different? Mummy operates with this basic model: handle all socket IO on one thread and dispatch incoming HTTP requests and WebSocket events to a pool of worker threads. Your HTTP handlers probably won't even need to think about threads at all. This model has many great benefits and is ready to take advantage of continued server core count increases (AMD just announced a 96 core 192 thread server CPU!). Why use Mummy instead of async? * No more needing to use {.async.}, Future[], await etc and deal with functions having colors. * Maintain the same excellent throughput of multiplexed nonblocking socket IO. * No concern that one blocking or expensive call will stall your entire server. * Async blocks on surprising things like DNS resolution and file reads which will stall all request handling. * Simpler to write request handlers. Blocking the thread is totally fine! Need to make a Postgres query? No problem, just wait for the results. * There is substantial advantage to writing simpler code vs theoretically fast but possibly convoluted and buggy code. * Much simpler debugging. Async stack traces are huge and confusing. * Easier error handling, just try except like you normally do. Uncaught exceptions in Mummy handlers also do not bring down your entire server. * Mummy handles the threading and dispatch so your handlers may not need to think about threads at all. * Takes advantage of multiple cores and the amazing work of the Nim team on ARC / ORC and Nim 2.0. Why prioritize WebSockets? WebSockets are wonderful and can have substantial advantages over more traditional API paradigms like REST and various flavors of RPC. Unfortunately, most HTTP servers pretend WebSockets don't exist. This means developers need to hack support in through additional dependencies, hijacking connections etc and it all rarely adds up into something really great. I see no reason why Websockets should not work exceptionally well right out of the box, saving developers a lot of uncertainty and time researching which of the possible ways to wedge WebSocket support in to an HTTP server is "best". What is Mummy not great for? Everything comes with trade-offs. Mummy is focused on being an exceptional API server. Think REST, JSON, RPC, WebSockets, HTML from templates etc. The property these share in common is they are all relatively memory-light. Most things are, which is great, but if you're specifically going to be serving a lot of very large files or expect large file uploads, Mummy is probably not the best choice unless your server has the RAM to handle the large files. Why is Mummy not great for large files? This is because Mummy dispatches fully received in-memory requests to worker threads and sends in-memory responses. This is great for everything except very large files. Example HTTP server import mummy, mummy/routers proc indexHandler(request: Request) = var headers: HttpHeaders headers["Content-Type"] = "text/plain" request.respond(200, headers, "Hello, World!") var router: Router router.get("/", indexHandler) let server = newServer(router) echo "Serving on http://localhost:8080" server.serve(Port(8080)) nim c --threads:on --mm:orc -r examples/basic_router.nim Example WebSocket server import mummy, mummy/routers proc indexHandler(request: Request) = var headers: HttpHeaders headers["Content-Type"] = "text/html" request.respond(200, headers, """ """) proc upgradeHandler(request: Request) = let websocket = request.upgradeToWebSocket() websocket.send("Hello world from WebSocket!") proc websocketHandler( websocket: WebSocket, event: WebSocketEvent, message: Message ) = case event: of OpenEvent: discard of MessageEvent: echo message.kind, ": ", message.data of ErrorEvent: discard of CloseEvent: discard var router: Router router.get("/", indexHandler) router.get("/ws", upgradeHandler) let server = newServer(router, websocketHandler) echo "Serving on http://localhost:8080" server.serve(Port(8080)) See the examples/ folder for more sample code, including an example WebSocket chat server. nim c --threads:on --mm:orc -r examples/basic_websockets.nim Performance Benchmarking HTTP servers is a bit like benchmarking running shoes. Certainly, there are some terrible shoes to run in (heels, clogs, etc), but once you're in a reasonable pair of shoes it is the runner that's going to matter, not the shoes. In this analogy, the runner is what your handlers are actually doing and the shoes are the HTTP server choice. With that in mind, I suggest three priorities: 1. Ensure your HTTP server choice does not unnecessarily hamper performance. 2. Avoid HTTP servers that have easy performance vulnerabilities. 3. Prioritize what will enable you to write and maintain performant and reliable handlers. I believe Mummy clears all three priorities: 1. Mummy prioritizes efficiency in receiving and dispatching incoming requests and sending outgoing responses. This means things like avoiding unnecessary memory copying, ensuring the CPU spends all of its time in your handlers. 2. Because Mummy uses multiplexed IO just like async, Mummy is not vulnerable to attacks like low-and-slow which traditionally multi-threaded servers are vulnerable to. Additionally, while a single blocking or CPU heavy operation can stall an entire async server, this is not a problem for Mummy. 3. Request handlers with Mummy are just plain-old inline Nim code. They have a straightforward request-in-response-out API. Keeping things simple is great for maintenance, reliability and performance. Benchmarks Benchmarking was done on an Ubuntu 22.04 server with a 4 core / 8 thread CPU. The tests/wrk_ servers that are being benchmarked attempt to simulate requests that take ~10ms to complete. All benchmarks were tested by: wrk -t10 -c100 -d10s http://localhost:8080 The exact commands for each server are: Mummy nim c --mm:orc --threads:on -d:release -r tests/wrk_mummy.nim Requests/sec: 9,547.56 AsyncHttpServer nim c --mm:orc --threads:off -d:release -r tests/ wrk_asynchttpserver.nim Requests/sec: 7,979.67 HttpBeast nim c --mm:orc --threads:on -d:release -r tests/wrk_httpbeast.nim Requests/sec: 9,862.00 Jester nim c --mm:orc --threads:off -d:release -r tests/wrk_jester.nim Requests/sec: 9,692.81 Prologue nim c --mm:orc --threads:off -d:release -r tests/wrk_prologue.nim Requests/sec: 9,749.22 NodeJS node tests/wrk_node.js Requests/sec: 8,544.60 Go go run tests/wrk_go.go Requests/sec: 9,171.55 Testing A fuzzer has been run against Mummy's socket reading and parsing code to ensure Mummy does not crash or otherwise misbehave on bad data from sockets. You can run the fuzzer any time by running nim c -r tests/fuzz_recv.nim. About An HTTP and WebSocket server for Nim that returns to the ancient ways of threads. Topics http web nim server websocket-server websocket websockets http-server Resources Readme License MIT license Stars 123 stars Watchers 5 watching Forks 6 forks Releases 6 0.2.4 Latest Dec 29, 2022 + 5 releases Contributors 3 * @guzba guzba Ryan Oldenburg * @treeform treeform Andre von Houck * @enthus1ast enthus1ast David Krause Languages * Nim 99.4% * Other 0.6% Footer (c) 2022 GitHub, Inc. Footer navigation * Terms * Privacy * Security * Status * Docs * Contact GitHub * Pricing * API * Training * Blog * About You can't perform that action at this time. You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.