digitalmars.D.announce - Release: serverino - please destroy it.
- Andrea Fontana (32/32) May 08 2022 Hello!
- Andrea Fontana (11/13) May 08 2022 Whoops, I forgot a couple of things. This was tested on linux
- Guillaume Piolat (3/5) May 12 2022 I tried to test servrino on WSL, but dub doesn't run on WSL.
- Andrea Fontana (7/14) May 12 2022 Hey thanks for your support!
- rikki cattermole (3/7) May 12 2022 It doesn't look like it is dub that is failing.
- Guillaume Piolat (4/6) May 12 2022 Well tbh, the simple fact that I would have to use WSL is a
- Andrea Fontana (6/13) May 12 2022 Yay. I need a Windows machine (or someone with it!) to rewrite
- =?UTF-8?Q?Ali_=c3=87ehreli?= (7/10) May 08 2022 Congratulations! :) Looking forward to watching your presentation at
- Andrea Fontana (6/17) May 08 2022 I wish I was able to speak publicly in English in front of an
- Adam Ruppe (3/5) May 08 2022 My cgi.d has used some fork approaches for a very long time since
- =?UTF-8?Q?Ali_=c3=87ehreli?= (14/19) May 08 2022 While we are on topic :) and as I finally understood what generational
- rikki cattermole (6/8) May 08 2022 This is not a D issue, its an implementation one.
- H. S. Teoh (11/21) May 08 2022 [...]
- =?UTF-8?Q?Ali_=c3=87ehreli?= (3/7) May 08 2022 Ooh! DConf is getting even more interesting. :o)
- Bruce Carneal (11/20) May 08 2022 A helpful paper: "Getting to Go: The Journey of Go's garbage
- Vladimir Panteleev (6/13) May 08 2022 Implementing write barriers in the compiler (by instrumenting
- H. S. Teoh (8/21) May 09 2022 Hmm, true. That puts a big damper on the possibilities... OTOH, if this
- Vladimir Panteleev (7/10) May 08 2022 I implemented one a long time ago. The only way to get write
- H. S. Teoh (6/17) May 09 2022 Interesting data point, in any case.
- Vladimir Panteleev (5/7) May 09 2022 Well, it's the only way I know of without making it a major
- H. S. Teoh (8/16) May 09 2022 Ah, gotcha. Yeah, I don't think such an approach would be fruitful (it
- Guillaume Piolat (2/7) May 09 2022 Looks very useful, congratulations!
- Andrea Fontana (4/14) May 09 2022 Thank you. Looking forward to getting feedback, bug reports and
- Adam Ruppe (3/5) May 10 2022 BTW I'm curious, what made you not want to use my cgi.d which has
- Andrea Fontana (7/12) May 10 2022 I was really tempted to start from that!
- Sebastiaan Koppe (11/24) May 09 2022 Typically server applications are IO heavy. I expect your
- Andrea Fontana (31/56) May 09 2022 I know. We all know :) Benchmarks are just benchmarks. They are
- Sebastiaan Koppe (15/44) May 10 2022 100msecs is on the upper end for sure, but if you add a database,
- Andrea Fontana (44/79) May 10 2022 Every server has its own target. BTW, I'm not developing
- Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= (6/7) May 10 2022 Requests tend to come in bursts from the same client, thanks to
- Andrea Fontana (19/26) May 10 2022 In my opnioni IRL that's not a big problem as it can seem.
- Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= (5/8) May 10 2022 Easy setup is probably the number one reason people land on a
- Andrea Fontana (10/18) May 10 2022 Right. But it's not just marketing.
- Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= (6/9) May 10 2022 Good point, there are more application areas than regular
- Andrea Fontana (5/14) May 10 2022 Indeed the "-ino" suffix in "serverino" stands for "small" in
- Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= (3/5) May 10 2022 Bambino > bambinello? So, the embedded-version could be
- Andrea Fontana (6/11) May 10 2022 Oh, italian is full of suffixes. -ello means a slightly different
- Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= (4/6) May 10 2022 Oh, and I loved the sound of it… suggests immaturity, perhaps?
- Andrea Fontana (7/13) May 10 2022 Maybe bambinetto is more about immaturity. Bambinuccio is cute.
- Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= (4/9) May 11 2022 Thanks for the explanation! <3
- Paolo Invernizzi (3/15) May 10 2022 Concordo ... (I agree!)
- Andrea Fontana (4/6) May 10 2022 Wait, you have always said you're not Italian. Have you changed
- Paolo Invernizzi (8/16) May 10 2022 Sinceramente non ricordo di averlo scritto, ma alla mia eta ...
- Andrea Fontana (6/13) May 10 2022 I wonder if you're making a fool of me. Or maybe it's me who is
- Paolo Invernizzi (3/18) May 10 2022 Here I am ... Milanese: https://www.deepglance.com/about
- Andrea Fontana (3/5) May 10 2022 Ok it's me getting old!
- Sebastiaan Koppe (10/20) May 10 2022 It is simple, since all your handler are effectively chained, any
- Andrea Fontana (12/36) May 10 2022 Not sure. What if your uda (regex) match is too permissive? Is
- Adam D Ruppe (12/13) May 10 2022 Well, cgi does one process per request, so there is no worker
- Andrea Fontana (21/34) May 10 2022 Some daemons can manage this by themselves (once again: check
- Orfeo (4/4) May 10 2022 well done Andrea!
- Andrea Fontana (4/8) May 11 2022 We all miss the good old bearophile!
- frame (9/13) May 14 2022 Take care of socket exceptions - especially if you want to make a
- Andrea Fontana (3/11) May 14 2022 Which kind of socket exception could be triggered by a client?
- frame (13/15) May 14 2022 It doesn't matter if triggered by a client or not, you need to
- Andrea Fontana (4/20) May 15 2022 Ok, added some checks on .select, .accept, .bind, .listen.
Hello! I've just released serverino. It's a small & ready-to-go http/https server. Every request is processed by a worker running in an isolated process, no fibers/threads, sorry (or thanks?) I did some tests and the performance sounds good: on a local machine it can handle more than 100_000 reqs/sec for a simple page containing just "hello world!".Of course that's not a good benchmark, if you can help me with other benchmarks it would be much appreciated (a big thanks to Tomáš Chaloupka who did some tests!) I'm trying to keep it simple and easy to compile. It has no external deps in its base configuration and only one external library (libretls) is required if you need/want to enable https. For your first project you need just three lines of code as you can see here: https://github.com/trikko/serverino/ I didn't implement a traditional router for uris as probably many of you expected. I use a different approach. Check out this example: https://github.com/trikko/serverino/#defining-more-than-one-endpoint This allows you to do some interesting things giving higher or lower priority to each endpoint (for example you can force something to always running first like redirect, logging, checks on login...) Instead of using a lot of different UDAs to set routing rules, you can simply write them in your endpoint's body and exit from it to pass to the next endpoint. Please help me testing it, I'm looking forward to receiving your shiny new issues on github. Dub package: https://code.dlang.org/packages/serverino Andrea
May 08 2022
On Sunday, 8 May 2022 at 21:32:42 UTC, Andrea Fontana wrote:[...] AndreaWhoops, I forgot a couple of things. This was tested on linux only and it should work fine on other posix systems (macOS included!). I don't have windows, but I think you need WSL to run it, since I'm using a lot of strange posix tricks to keep performace at a good level (like sending opened file descriptors between processes thru sockets). If you can test it on windows with WSL, that would be appreciated a lot! Andrea
May 08 2022
On Sunday, 8 May 2022 at 21:45:28 UTC, Andrea Fontana wrote:If you can test it on windows with WSL, that would be appreciated a lot!I tried to test servrino on WSL, but dub doesn't run on WSL. => https://github.com/dlang/dub/issues/2249
May 12 2022
On Thursday, 12 May 2022 at 10:26:28 UTC, Guillaume Piolat wrote:On Sunday, 8 May 2022 at 21:45:28 UTC, Andrea Fontana wrote:Hey thanks for your support! Too bad dub doesn't work with wsl, it sounds like a lost opportunity. Does dmd/rdmd work? Serverino uses std.net.curl just for running its unittests, so maybe that bug is not blocking. AndreaIf you can test it on windows with WSL, that would be appreciated a lot!I tried to test servrino on WSL, but dub doesn't run on WSL. => https://github.com/dlang/dub/issues/2249
May 12 2022
On 12/05/2022 11:33 PM, Andrea Fontana wrote:Too bad dub doesn't work with wsl, it sounds like a lost opportunity. Does dmd/rdmd work? Serverino uses std.net.curl just for running its unittests, so maybe that bug is not blocking.It doesn't look like it is dub that is failing. This is a problem in Phobos/compiler.
May 12 2022
On Thursday, 12 May 2022 at 11:33:07 UTC, Andrea Fontana wrote:Does dmd/rdmd work? Serverino uses std.net.curl just for running its unittests, so maybe that bug is not blocking.Well tbh, the simple fact that I would have to use WSL is a blocker for me. AFAIK vibe or cgi.d do not require that.
May 12 2022
On Thursday, 12 May 2022 at 11:46:05 UTC, Guillaume Piolat wrote:On Thursday, 12 May 2022 at 11:33:07 UTC, Andrea Fontana wrote:Yay. I need a Windows machine (or someone with it!) to rewrite some POSIX parts. For example the part that send/receive the file descriptor (of a socket) from the master process to the worker (windows has its own API for this)Does dmd/rdmd work? Serverino uses std.net.curl just for running its unittests, so maybe that bug is not blocking.Well tbh, the simple fact that I would have to use WSL is a blocker for me. AFAIK vibe or cgi.d do not require that.
May 12 2022
Congratulations! :) Looking forward to watching your presentation at DConf... ;) On 5/8/22 14:32, Andrea Fontana wrote:Every request is processed by a worker running in an isolated process, no fibers/threads, sorry (or thanks?)That effectively uses multiple GCs. I always suspected that approach would provide better latency.sending opened file descriptors between processes thru socketsSweet! Ali
May 08 2022
On Sunday, 8 May 2022 at 22:09:37 UTC, Ali Çehreli wrote:Congratulations! :) Looking forward to watching your presentation at DConf... ;)I wish I was able to speak publicly in English in front of an audience :)On 5/8/22 14:32, Andrea Fontana wrote:I think it depends on what your server is doing, anyway.Every request is processed by a worker running in an isolatedprocess,no fibers/threads, sorry (or thanks?)That effectively uses multiple GCs. I always suspected that approach would provide better latency.I sent a pull request (merged!) for druntime to make this work on macOS too!sending opened file descriptors between processes thru socketsSweet! Ali
May 08 2022
On Sunday, 8 May 2022 at 22:09:37 UTC, Ali Çehreli wrote:That effectively uses multiple GCs. I always suspected that approach would provide better latency.My cgi.d has used some fork approaches for a very long time since it is a very simple way to spread this out, it works quite well.
May 08 2022
On 5/8/22 16:10, Adam Ruppe wrote:On Sunday, 8 May 2022 at 22:09:37 UTC, Ali Çehreli wrote:While we are on topic :) and as I finally understood what generational GC is[1], are there any fundamental issues with D to not use one? Ali [1] Translating from what I wrote in the Turkish forum, here is my current understanding: Let's not waste time checking all allocated memory at every GC cycle. Instead, let's be smarter and assume that memory that survived through this GC cycle will survive the next cycle as well. Let's put those memory blocks aside to be reconsidered only when we really have to. This effectively makes the GC only play with short-lived objects, reducing the amount of memory touched. This would make some objects live forever, but GC never promises that all finalizers will be executed.That effectively uses multiple GCs. I always suspected that approach would provide better latency.My cgi.d has used some fork approaches for a very long time since it is a very simple way to spread this out, it works quite well.
May 08 2022
On 09/05/2022 11:44 AM, Ali Çehreli wrote:While we are on topic :) and as I finally understood what generational GC is[1], are there any fundamental issues with D to not use one?This is not a D issue, its an implementation one. We don't have write barriers, that's it. Make them opt-in and we can have more advanced GC's. Oh and book recommendation for the subject: https://www.amazon.com/Garbage-Collection-Handbook-Management-Algorithms/dp/1420082795
May 08 2022
On Mon, May 09, 2022 at 12:10:53PM +1200, rikki cattermole via Digitalmars-d-announce wrote:On 09/05/2022 11:44 AM, Ali Çehreli wrote:[...] In the past, the argument was that write barriers represented an unacceptable performance hit to D code. But I don't think this has ever actually been measured. (Or has it?) Maybe somebody should make a dmd fork that introduces write barriers, plus a generational GC (even if it's a toy, proof-of-concept-only implementation) to see if the performance hit is really as bad as believed to be. T -- The best way to destroy a cause is to defend it poorly.While we are on topic :) and as I finally understood what generational GC is[1], are there any fundamental issues with D to not use one?This is not a D issue, its an implementation one. We don't have write barriers, that's it. Make them opt-in and we can have more advanced GC's.
May 08 2022
On 5/8/22 17:25, H. S. Teoh wrote:somebody should make a dmd fork that introduces write barriers, plus a generational GC (even if it's a toy, proof-of-concept-only implementation) to see if the performance hit is really as bad as believed to be.Ooh! DConf is getting even more interesting. :o) Ali
May 08 2022
On Monday, 9 May 2022 at 00:32:33 UTC, Ali Çehreli wrote:On 5/8/22 17:25, H. S. Teoh wrote:A helpful paper: "Getting to Go: The Journey of Go's garbage collector". Positive highlights: 1) non-copying 2) no read barriers Less friendly: 1) write barriers 2) GC aware fiber scheduler 3) other??? Would be some (huge amount?) of work but porting/enabling an opt-in golang latency GC could be a big enabler for the casual/soft "real time" crowd. Here's a link to the paper: https://go.dev/blog/ismmkeynotesomebody should make a dmd fork that introduces write barriers, plus a generational GC(even ifit's a toy, proof-of-concept-only implementation) to see iftheperformance hit is really as bad as believed to be.Ooh! DConf is getting even more interesting. :o) Ali
May 08 2022
On Monday, 9 May 2022 at 00:25:43 UTC, H. S. Teoh wrote:In the past, the argument was that write barriers represented an unacceptable performance hit to D code. But I don't think this has ever actually been measured. (Or has it?) Maybe somebody should make a dmd fork that introduces write barriers, plus a generational GC (even if it's a toy, proof-of-concept-only implementation) to see if the performance hit is really as bad as believed to be.Implementing write barriers in the compiler (by instrumenting code) means that you're no longer allowed to copy pointers to managed memory in non-D code. This is a stricter assumption that the current ones we have; for instance, copying a struct (which has indirections) with memcpy would be forbidden.
May 08 2022
On Mon, May 09, 2022 at 05:55:39AM +0000, Vladimir Panteleev via Digitalmars-d-announce wrote:On Monday, 9 May 2022 at 00:25:43 UTC, H. S. Teoh wrote:Hmm, true. That puts a big damper on the possibilities... OTOH, if this could be made an optional feature, then code that we know doesn't need, e.g., passing pointers to C code, can take advantage of possibly better GC strategies. T -- English has the lovely word "defenestrate", meaning "to execute by throwing someone out a window", or more recently "to remove Windows from a computer and replace it with something useful". :-) -- John CowanIn the past, the argument was that write barriers represented an unacceptable performance hit to D code. But I don't think this has ever actually been measured. (Or has it?) Maybe somebody should make a dmd fork that introduces write barriers, plus a generational GC (even if it's a toy, proof-of-concept-only implementation) to see if the performance hit is really as bad as believed to be.Implementing write barriers in the compiler (by instrumenting code) means that you're no longer allowed to copy pointers to managed memory in non-D code. This is a stricter assumption that the current ones we have; for instance, copying a struct (which has indirections) with memcpy would be forbidden.
May 09 2022
On Sunday, 8 May 2022 at 23:44:42 UTC, Ali Çehreli wrote:While we are on topic :) and as I finally understood what generational GC is[1], are there any fundamental issues with D to not use one?I implemented one a long time ago. The only way to get write barriers with D is memory protection. It worked, but unfortunately the write barriers caused a severe performance penalty. It's possible that it might be viable with more tweaking, or in certain applications where most of the heap is not written to; I did not experiment a lot with it.
May 08 2022
On Mon, May 09, 2022 at 05:52:30AM +0000, Vladimir Panteleev via Digitalmars-d-announce wrote:On Sunday, 8 May 2022 at 23:44:42 UTC, Ali Çehreli wrote:Why is memory protection the only way to implement write barriers in D?While we are on topic :) and as I finally understood what generational GC is[1], are there any fundamental issues with D to not use one?I implemented one a long time ago. The only way to get write barriers with D is memory protection. It worked, but unfortunately the write barriers caused a severe performance penalty.It's possible that it might be viable with more tweaking, or in certain applications where most of the heap is not written to; I did not experiment a lot with it.Interesting data point, in any case. T -- The early bird gets the worm. Moral: ewww...
May 09 2022
On Monday, 9 May 2022 at 16:37:15 UTC, H. S. Teoh wrote:Why is memory protection the only way to implement write barriers in D?Well, it's the only way I know of without making it a major backwards-incompatible change. The main restriction in this area is that it must continue working with code written in other languages, and generally not affect the ABI drastically.
May 09 2022
On Mon, May 09, 2022 at 04:48:11PM +0000, Vladimir Panteleev via Digitalmars-d-announce wrote:On Monday, 9 May 2022 at 16:37:15 UTC, H. S. Teoh wrote:Ah, gotcha. Yeah, I don't think such an approach would be fruitful (it was worth a shot, though!). If D were ever to get write barriers, they'd have to be in some other form, probably more intrusive in terms of backwards-compatibility and ABI. T -- Curiosity kills the cat. Moral: don't be the cat.Why is memory protection the only way to implement write barriers in D?Well, it's the only way I know of without making it a major backwards-incompatible change. The main restriction in this area is that it must continue working with code written in other languages, and generally not affect the ABI drastically.
May 09 2022
On Sunday, 8 May 2022 at 21:32:42 UTC, Andrea Fontana wrote:Hello! I've just released serverino. It's a small & ready-to-go http/https server. Dub package: https://code.dlang.org/packages/serverino AndreaLooks very useful, congratulations!
May 09 2022
On Monday, 9 May 2022 at 19:09:40 UTC, Guillaume Piolat wrote:On Sunday, 8 May 2022 at 21:32:42 UTC, Andrea Fontana wrote:Thank you. Looking forward to getting feedback, bug reports and help :) AndreaHello! I've just released serverino. It's a small & ready-to-go http/https server. Dub package: https://code.dlang.org/packages/serverino AndreaLooks very useful, congratulations!
May 09 2022
On Monday, 9 May 2022 at 19:20:27 UTC, Andrea Fontana wrote:Thank you. Looking forward to getting feedback, bug reports and help :)BTW I'm curious, what made you not want to use my cgi.d which has similar capabilities?
May 10 2022
On Tuesday, 10 May 2022 at 15:01:43 UTC, Adam Ruppe wrote:On Monday, 9 May 2022 at 19:20:27 UTC, Andrea Fontana wrote:I was really tempted to start from that! But it's difficult to fork and edit a 11kloc project like that :) I had yet developed fastcgi and scgi code in the past so I've reused some code and it didn't take so much time to get to serverino. AndreaThank you. Looking forward to getting feedback, bug reports and help :)BTW I'm curious, what made you not want to use my cgi.d which has similar capabilities?
May 10 2022
On Sunday, 8 May 2022 at 21:32:42 UTC, Andrea Fontana wrote:Every request is processed by a worker running in an isolated process, no fibers/threads, sorry (or thanks?) I did some tests and the performance sounds good: on a local machine it can handle more than 100_000 reqs/sec for a simple page containing just "hello world!".Of course that's not a good benchmark, if you can help me with other benchmarks it would be much appreciated (a big thanks to Tomáš Chaloupka who did some tests!)Typically server applications are IO heavy. I expect your isolated-process approach to break down with that kind of work. As an example, how many requests per second can you manage if all requests have to wait 100 msecs? For non critical workload you will probably still hit good enough performance though.Instead of using a lot of different UDAs to set routing rules, you can simply write them in your endpoint's body and exit from it to pass to the next endpoint.My experience is that exhaustive matching is easier to reason about at larger scale.Please help me testing it, I'm looking forward to receiving your shiny new issues on github.I noticed it has zero unittests, that is probably a good place to start.
May 09 2022
On Monday, 9 May 2022 at 20:08:38 UTC, Sebastiaan Koppe wrote:On Sunday, 8 May 2022 at 21:32:42 UTC, Andrea Fontana wrote:I know. We all know :) Benchmarks are just benchmarks. They are useful to understand how much overhead your server adds to the whole project. These benchmarks are made in the local machine, with almost no connection overhead. Not every application is IO heavy, anyway.Every request is processed by a worker running in an isolated process, no fibers/threads, sorry (or thanks?) I did some tests and the performance sounds good: on a local machine it can handle more than 100_000 reqs/sec for a simple page containing just "hello world!".Of course that's not a good benchmark, if you can help me with other benchmarks it would be much appreciated (a big thanks to Tomáš Chaloupka who did some tests!)Typically server applications are IO heavy. I expect your isolated-process approach to break down with that kind of work.As an example, how many requests per second can you manage if all requests have to wait 100 msecs? For non critical workload you will probably still hit good enough performance though.Firstly, it depends on how many workers you have. Then you should consider that a lot of (most?) websites use php-fpm, that works using the same approach (but php is much slower than D). The same goes for cgi/fastcgi/scgi and so on. Let's say you have just 20 workers. 100msecs for each request (a lot of time for my standards, I would say). That means 20*10 = 200 webpages/s = 720k pages/h. I don't think your website has so much traffic... And I hope not every request will take 100msecs!Yes, but exactly the same thing can be done without uda. ``` endpoint void my_end(Request r, Output o) { if (r.uri == "/asd") // or whatever you want: regex, or checking another field return false; // } ``` This is just like: ``` matchuda(uri, "/asd") void my_end(....) { ... } ``` What's the difference? The first one is much more flexible, IMHO.Instead of using a lot of different UDAs to set routing rules, you can simply write them in your endpoint's body and exit from it to pass to the next endpoint.My experience is that exhaustive matching is easier to reason about at larger scale.Please help me testing it, I'm looking forward to receiving your shiny new issues on github.I noticed it has zero unittests, that is probably a good place to start.Of course! They will come for sure. :) Andrea
May 09 2022
On Monday, 9 May 2022 at 20:37:50 UTC, Andrea Fontana wrote:On Monday, 9 May 2022 at 20:08:38 UTC, Sebastiaan Koppe wrote:100msecs is on the upper end for sure, but if you add a database, external service call, etc. it is not uncommon to reach that. The point however, is that the architecture breaks down because it is unable to do work concurrently. Every requests blocks a worker from start to finish. Unless it is CPU heavy the system will be under utilized. That is not necessarily bad though. The simplicity has something going for it, but it is definitely a tradeoff that you should consider highlighting.As an example, how many requests per second can you manage if all requests have to wait 100 msecs? For non critical workload you will probably still hit good enough performance though.Firstly, it depends on how many workers you have. Then you should consider that a lot of (most?) websites use php-fpm, that works using the same approach (but php is much slower than D). The same goes for cgi/fastcgi/scgi and so on. Let's say you have just 20 workers. 100msecs for each request (a lot of time for my standards, I would say). That means 20*10 = 200 webpages/s = 720k pages/h. I don't think your website has so much traffic... And I hope not every request will take 100msecs!``` endpoint void my_end(Request r, Output o) { if (r.uri == "/asd") // or whatever you want: regex, or checking another field return false; // } ``` This is just like: ``` matchuda(uri, "/asd") void my_end(....) { ... } ``` What's the difference? The first one is much more flexible, IMHO.The difference is that with the route uda you can *only* map routes 1:1 exhaustively. With your approach it is up to the programmer to avoid errors. It is also hard to reason about the flow of requests through all those functions, and you have to look at the body of them to determine what will happen.
May 10 2022
On Tuesday, 10 May 2022 at 08:32:15 UTC, Sebastiaan Koppe wrote:On Monday, 9 May 2022 at 20:37:50 UTC, Andrea Fontana wrote:And you can still handle 700k/views per hour with 20 workers!On Monday, 9 May 2022 at 20:08:38 UTC, Sebastiaan Koppe wrote:100msecs is on the upper end for sure, but if you add a database, external service call, etc. it is not uncommon to reach that.As an example, how many requests per second can you manage if all requests have to wait 100 msecs? For non critical workload you will probably still hit good enough performance though.Firstly, it depends on how many workers you have. Then you should consider that a lot of (most?) websites use php-fpm, that works using the same approach (but php is much slower than D). The same goes for cgi/fastcgi/scgi and so on. Let's say you have just 20 workers. 100msecs for each request (a lot of time for my standards, I would say). That means 20*10 = 200 webpages/s = 720k pages/h. I don't think your website has so much traffic... And I hope not every request will take 100msecs!The point however, is that the architecture breaks down because it is unable to do work concurrently. Every requests blocks a worker from start to finish. Unless it is CPU heavy the system will be under utilized. That is not necessarily bad though. The simplicity has something going for it, but it is definitely a tradeoff that you should consider highlighting.Every server has its own target. BTW, I'm not developing serverino to use it as a building block of a CDN. In real-life projects, I think you can use it without any problem for not-huge projects. You can also put it under a reverse proxy (f.e. nginx), to handle just the requests you need to write in D.The difference is that with the route uda you can *only* map routes 1:1 exhaustively. With your approach it is up to the programmer to avoid errors. It is also hard to reason about the flow of requests through all those functions, and you have to look at the body of them to determine what will happen.Sorry I don't follow you: I don't know which framework you're using, but if you're using UDA with matches (something like: matchUri("/main") void renderMain(...) { ... }) you still have to check all the functions if a request is not handled correctly. Or am I missing something? Using my approach if you want to check which functions escape from routing you can just add a catch-all endpoint with low priority. ``` priority(-1000) endpoint void wtf(Request r, Output o) { fatal("Request NOT HANDLED: ", r.dump()); } ``` And if a request doesn't match your UDA constraint, how do you debug what's wrong with it? I think it's easier to add a checkpoint/log on the first lines of your functions body to guess why the function is skipped. In any case if you want to use a different routing strategy it's quite easy. I really don't like libraries that force you to use their own style/way. So you can even drop my UDAs and write the app like this. It still works: ``` mixin ServerinoMain; void entry(Request r, Output o) { // Use your routing strategy here // ... // YourRouter router; // router.do(r, "/hello/world", &yourFunction); // router.do(r, "/bla", &hello); } ``` Andrea
May 10 2022
On Tuesday, 10 May 2022 at 10:49:06 UTC, Andrea Fontana wrote:And you can still handle 700k/views per hour with 20 workers!Requests tend to come in bursts from the same client, thanks to clunky javascript APIs and clutters of resources (and careless web developers). For a typical D user ease-of-use is probably more important at this point, though, so good luck with your project!
May 10 2022
On Tuesday, 10 May 2022 at 12:31:23 UTC, Ola Fosheim Grøstad wrote:On Tuesday, 10 May 2022 at 10:49:06 UTC, Andrea Fontana wrote:In my opnioni IRL that's not a big problem as it can seem. Again: that's just how nginx and apache handle php/cgi/fcgi/scgi requests. Wikipedia runs wikimedia software. Written in php. Running on apache with php-fpm (and cache!). And I'm not suggesting to run wikipedia on serverino, *for now*. If you try to open a lot of wikipedia pages at the same time in a burst, they will be served (probably using keep-alive connection) not in parallel: you're queued. And the 99.9% of users will never notice this. Is it a problem? If you need much control, you can use an http accelerator and/or you can use a reverse proxy (like nginx) to control bursts et similia. I'm running a whole website in D using fastcgi and we have no problem at all, it's blazing fast. But it's not so easy to setup as serverino :) AndreaAnd you can still handle 700k/views per hour with 20 workers!Requests tend to come in bursts from the same client, thanks to clunky javascript APIs and clutters of resources (and careless web developers). For a typical D user ease-of-use is probably more important at this point, though, so good luck with your project!
May 10 2022
On Tuesday, 10 May 2022 at 12:52:01 UTC, Andrea Fontana wrote:I'm running a whole website in D using fastcgi and we have no problem at all, it's blazing fast. But it's not so easy to setup as serverino :)Easy setup is probably the number one reason people land on a specific web-tech, so it is the best initial angle, I agree. (By version 3.x you know what the practical weak spots are and can rethink the bottom layer.)
May 10 2022
On Tuesday, 10 May 2022 at 13:15:38 UTC, Ola Fosheim Grøstad wrote:On Tuesday, 10 May 2022 at 12:52:01 UTC, Andrea Fontana wrote:Right. But it's not just marketing. I work in the R&D and every single time I even have to write a small api or a simple html interface to control some strange machine I think "omg, I have to set nginx agaaaaaain". It's pretty annoying especially if you're working on shared aws machine. (I know, docker & c. Exist, but they take a lot to setup and they are heavy for some simple api). I'm going to love serverino in the next months :)I'm running a whole website in D using fastcgi and we have no problem at all, it's blazing fast. But it's not so easy to setup as serverino :)Easy setup is probably the number one reason people land on a specific web-tech, so it is the best initial angle, I agree. (By version 3.x you know what the practical weak spots are and can rethink the bottom layer.)
May 10 2022
On Tuesday, 10 May 2022 at 15:00:06 UTC, Andrea Fontana wrote:I work in the R&D and every single time I even have to write a small api or a simple html interface to control some strange machine I think "omg, I have to set nginx agaaaaaain".Good point, there are more application areas than regular websites. Embedded remote applications could be another application area where you want something simple with HTTPS (monitoring webcams, sensors, solar panels, supervising farming houses or whatever).
May 10 2022
On Tuesday, 10 May 2022 at 15:16:22 UTC, Ola Fosheim Grøstad wrote:On Tuesday, 10 May 2022 at 15:00:06 UTC, Andrea Fontana wrote:Indeed the "-ino" suffix in "serverino" stands for "small" in italian. :) AndreaI work in the R&D and every single time I even have to write a small api or a simple html interface to control some strange machine I think "omg, I have to set nginx agaaaaaain".Good point, there are more application areas than regular websites. Embedded remote applications could be another application area where you want something simple with HTTPS (monitoring webcams, sensors, solar panels, supervising farming houses or whatever).
May 10 2022
On Tuesday, 10 May 2022 at 15:27:48 UTC, Andrea Fontana wrote:Indeed the "-ino" suffix in "serverino" stands for "small" in italian. :)Bambino > bambinello? So, the embedded-version could be «serverinello»? :O)
May 10 2022
On Tuesday, 10 May 2022 at 15:35:35 UTC, Ola Fosheim Grøstad wrote:On Tuesday, 10 May 2022 at 15:27:48 UTC, Andrea Fontana wrote:Oh, italian is full of suffixes. -ello means a slightly different thing. It's small but sounds like a bit pejorative. -ino in bambino is not (anymore) a suffix, anyway. AndreaIndeed the "-ino" suffix in "serverino" stands for "small" in italian. :)Bambino > bambinello? So, the embedded-version could be «serverinello»? :O)
May 10 2022
On Tuesday, 10 May 2022 at 16:05:11 UTC, Andrea Fontana wrote:Oh, italian is full of suffixes. -ello means a slightly different thing. It's small but sounds like a bit pejorative.Oh, and I loved the sound of it… suggests immaturity, perhaps? (I love the -ello and -ella endings. «Bambinella» is one of my favourite words, turns out it is a fruit too!)
May 10 2022
On Tuesday, 10 May 2022 at 16:47:13 UTC, Ola Fosheim Grøstad wrote:On Tuesday, 10 May 2022 at 16:05:11 UTC, Andrea Fontana wrote:Maybe bambinetto is more about immaturity. Bambinuccio is cute. Bambinaccio is bad. Bambinone is big (an adult that behave like a child). -ello doesn't sound good with bambino, but it's very similar to -etto. Good luck :)Oh, italian is full of suffixes. -ello means a slightly different thing. It's small but sounds like a bit pejorative.Oh, and I loved the sound of it… suggests immaturity, perhaps? (I love the -ello and -ella endings. «Bambinella» is one of my favourite words, turns out it is a fruit too!)
May 10 2022
On Tuesday, 10 May 2022 at 19:24:25 UTC, Andrea Fontana wrote:Maybe bambinetto is more about immaturity. Bambinuccio is cute. Bambinaccio is bad. Bambinone is big (an adult that behave like a child). -ello doesn't sound good with bambino, but it's very similar to -etto. Good luck :)Thanks for the explanation! <3 If only programming languages were this expressive! «Servinuccio»… ;P
May 11 2022
On Tuesday, 10 May 2022 at 16:05:11 UTC, Andrea Fontana wrote:On Tuesday, 10 May 2022 at 15:35:35 UTC, Ola Fosheim Grøstad wrote:Concordo ... (I agree!) :-POn Tuesday, 10 May 2022 at 15:27:48 UTC, Andrea Fontana wrote:Oh, italian is full of suffixes. -ello means a slightly different thing. It's small but sounds like a bit pejorative. -ino in bambino is not (anymore) a suffix, anyway. AndreaIndeed the "-ino" suffix in "serverino" stands for "small" in italian. :)Bambino > bambinello? So, the embedded-version could be «serverinello»? :O)
May 10 2022
On Tuesday, 10 May 2022 at 19:50:08 UTC, Paolo Invernizzi wrote:Concordo ... (I agree!) :-PWait, you have always said you're not Italian. Have you changed your mind? Andrea
May 10 2022
On Tuesday, 10 May 2022 at 19:55:32 UTC, Andrea Fontana wrote:On Tuesday, 10 May 2022 at 19:50:08 UTC, Paolo Invernizzi wrote:Sinceramente non ricordo di averlo scritto, ma alla mia eta ... probabilmente dimentico qualcosa ... comunque piacere! E' bello vedere altri italiani apprezzare questo magnifico linguaggio! (Frankly speaking, I don't remember to have written that, but hey, I'm getting old ... probably I'm forgetting something ... anyway nice to meet you! It's great to see Italians here enjoying this great programming language!)Concordo ... (I agree!) :-PWait, you have always said you're not Italian. Have you changed your mind? Andrea
May 10 2022
On Tuesday, 10 May 2022 at 20:13:45 UTC, Paolo Invernizzi wrote:Sinceramente non ricordo di averlo scritto, ma alla mia eta ... probabilmente dimentico qualcosa ... comunque piacere! E' bello vedere altri italiani apprezzare questo magnifico linguaggio! (Frankly speaking, I don't remember to have written that, but hey, I'm getting old ... probably I'm forgetting something ... anyway nice to meet you! It's great to see Italians here enjoying this great programming language!)I wonder if you're making a fool of me. Or maybe it's me who is getting old. I'm pretty sure that there's a user here with a really Italian name who was born somewhere in South America. Andrea
May 10 2022
On Tuesday, 10 May 2022 at 20:41:17 UTC, Andrea Fontana wrote:On Tuesday, 10 May 2022 at 20:13:45 UTC, Paolo Invernizzi wrote:Here I am ... Milanese: https://www.deepglance.com/about /PaoloSinceramente non ricordo di averlo scritto, ma alla mia eta ... probabilmente dimentico qualcosa ... comunque piacere! E' bello vedere altri italiani apprezzare questo magnifico linguaggio! (Frankly speaking, I don't remember to have written that, but hey, I'm getting old ... probably I'm forgetting something ... anyway nice to meet you! It's great to see Italians here enjoying this great programming language!)I wonder if you're making a fool of me. Or maybe it's me who is getting old. I'm pretty sure that there's a user here with a really Italian name who was born somewhere in South America. Andrea
May 10 2022
On Tuesday, 10 May 2022 at 21:24:46 UTC, Paolo Invernizzi wrote:Here I am ... Milanese: https://www.deepglance.com/about /PaoloOk it's me getting old! Andrea
May 10 2022
On Tuesday, 10 May 2022 at 10:49:06 UTC, Andrea Fontana wrote:On Tuesday, 10 May 2022 at 08:32:15 UTC, Sebastiaan Koppe wrote:It is simple, since all your handler are effectively chained, any error in any one of them can cause later ones to fail or misbehave. This decreases locality and increases the things you have to reason about. There are other benefits to uda tagged endpoints too, for example they are easier to nest, or to programmatically generate them. In vibe-d I added the default option of generating OPTION handlers for every regular endpoint. This is required for CORS.The difference is that with the route uda you can *only* map routes 1:1 exhaustively. With your approach it is up to the programmer to avoid errors. It is also hard to reason about the flow of requests through all those functions, and you have to look at the body of them to determine what will happen.Sorry I don't follow youIn any case if you want to use a different routing strategy it's quite easy. I really don't like libraries that force you to use their own style/way.That is good.
May 10 2022
On Tuesday, 10 May 2022 at 18:33:18 UTC, Sebastiaan Koppe wrote:On Tuesday, 10 May 2022 at 10:49:06 UTC, Andrea Fontana wrote:Not sure. What if your uda (regex) match is too permissive? Is that different? My code evaluates workers in order, just like yours, no? Maybe I can enable some log if set on config, to track what's happening. That could help you to debug if something goes wrong.On Tuesday, 10 May 2022 at 08:32:15 UTC, Sebastiaan Koppe wrote:It is simple, since all your handler are effectively chained, any error in any one of them can cause later ones to fail or misbehave. This decreases locality and increases the things you have to reason about.The difference is that with the route uda you can *only* map routes 1:1 exhaustively. With your approach it is up to the programmer to avoid errors. It is also hard to reason about the flow of requests through all those functions, and you have to look at the body of them to determine what will happen.Sorry I don't follow youThere are other benefits to uda tagged endpoints too, for example they are easier to nest, or to programmatically generate them. In vibe-d I added the default option of generating OPTION handlers for every regular endpoint. This is required for CORS.endpoint void func(...){ if(req.method == Method.OPTION){ // THIS RUN FOR EVERY ENDPOINT } }AndreaIn any case if you want to use a different routing strategy it's quite easy. I really don't like libraries that force you to use their own style/way.That is good.
May 10 2022
On Monday, 9 May 2022 at 20:37:50 UTC, Andrea Fontana wrote:The same goes for cgi/fastcgi/scgi and so on.Well, cgi does one process per request, so there is no worker pool (it is the original "serverless" lol). fastcgi is interesting because the Apache module for it will actually start and stop worker processes as-needed. I don't think the the nginx impl does that though. But the nicest thing about all these application models is if you write it in the right way, you can swap out the approach, either transparently adding the i/o event waits or just adding additional servers without touching the application code. That's a lot harder to do when you expect shared state etc. like other things encourage.
May 10 2022
On Tuesday, 10 May 2022 at 13:34:27 UTC, Adam D Ruppe wrote:On Monday, 9 May 2022 at 20:37:50 UTC, Andrea Fontana wrote:Some daemons can manage this by themselves (once again: check php-fpm "dynamic" setting). Serverino can do it as well. You can set in configuration the max and min number of workers. It's easy: ``` onServerInit auto setup() { ServerinoConfig sc = ServerinoConfig.create(); sc.setMinWorkers(5); sc.setMaxWorkers(100); return sc; } ``` If all workers are busy the daemon will launch a new one. You might be interested in setMaxWorkerLifetime() and sc.setMaxWorkerIdling() too!The same goes for cgi/fastcgi/scgi and so on.Well, cgi does one process per request, so there is no worker pool (it is the original "serverless" lol). fastcgi is interesting because the Apache module for it will actually start and stop worker processes as-needed. I don't think the the nginx impl does that though.But the nicest thing about all these application models is if you write it in the right way, you can swap out the approach, either transparently adding the i/o event waits or just adding additional servers without touching the application code. That's a lot harder to do when you expect shared state etc. like other things encourage.I would mention that if something goes wrong and a process crash or get caught in an infinite loop, it's not a problem. Process is killed and wake up again without pull all the server down. Andrea
May 10 2022
well done Andrea! (forum begins to be too crowded with Italians :) ) --- Orfeo
May 10 2022
On Wednesday, 11 May 2022 at 06:50:37 UTC, Orfeo wrote:well done Andrea! (forum begins to be too crowded with Italians :) ) --- OrfeoWe all miss the good old bearophile! I think the most active italian in this forum. Andrea
May 11 2022
On Sunday, 8 May 2022 at 21:32:42 UTC, Andrea Fontana wrote:Please help me testing it, I'm looking forward to receiving your shiny new issues on github. Dub package: https://code.dlang.org/packages/serverino AndreaTake care of socket exceptions - especially if you want to make a port to Windows. You should always expect one. It's not enough to test `Socket.isAlive` - a client socket may be faulty and any illegal socket operation throws and kills your loop. Even if `isAlive` works as expected, it may changes the status before you have add the socket to the set. You don't want your server to crash if a client misbehaves.
May 14 2022
On Saturday, 14 May 2022 at 20:44:54 UTC, frame wrote:Take care of socket exceptions - especially if you want to make a port to Windows. You should always expect one. It's not enough to test `Socket.isAlive` - a client socket may be faulty and any illegal socket operation throws and kills your loop. Even if `isAlive` works as expected, it may changes the status before you have add the socket to the set. You don't want your server to crash if a client misbehaves.Which kind of socket exception could be triggered by a client? Andrea
May 14 2022
On Saturday, 14 May 2022 at 23:23:47 UTC, Andrea Fontana wrote:Which kind of socket exception could be triggered by a client? AndreaIt doesn't matter if triggered by a client or not, you need to deal with the possibility. A closed/destroyed socket is an invalid resource. I recently had the scenario on Windows where a client crashed and the socket wasn't closed properly somehow. Now the server adds the socket to the set to see an update - boom! "Socket operation on non-socket" error. Also accepting sockets can throw, for eg. by a stupid network time out error - not only on Windows. Other socket operations are no exceptions either. `isAlive` is fine for properly shutdowned/closed sockets by you or peer. But it doesn't protect you from faulting ones.
May 14 2022
On Sunday, 15 May 2022 at 06:37:08 UTC, frame wrote:On Saturday, 14 May 2022 at 23:23:47 UTC, Andrea Fontana wrote:Ok, added some checks on .select, .accept, .bind, .listen. Thank you. AndreaWhich kind of socket exception could be triggered by a client? AndreaIt doesn't matter if triggered by a client or not, you need to deal with the possibility. A closed/destroyed socket is an invalid resource. I recently had the scenario on Windows where a client crashed and the socket wasn't closed properly somehow. Now the server adds the socket to the set to see an update - boom! "Socket operation on non-socket" error. Also accepting sockets can throw, for eg. by a stupid network time out error - not only on Windows. Other socket operations are no exceptions either. `isAlive` is fine for properly shutdowned/closed sockets by you or peer. But it doesn't protect you from faulting ones.
May 15 2022