Why I wrote the fx web server
21 points by rikhuijzer
21 points by rikhuijzer
I feel like it’s more of a CMS than a web server
The author calls WordPress a server as well. Maybe something is being lost in translation.
(sorry for the technical digression, I know it’s not really the point of the article…)
I just had a quick look at the source code. I looks neat to my eyes. It’s funny because I’m working on a completely unrelated hobby project (a web app as well, but not microblogging) with a very similar tech stack, i.e. Rust, axum, and rusqlite. I spent quite a bit of time fighting against the compiler until I have understood that rusqlite code have to be somewhat isolated from async axum handlers, because rusqlite::Statement is !Send and !Sync… so I use #[axum::debug_handler]
everywhere now, it really helps troubleshooting. On the other hand, in your case I guess the mutex in ServerContext also helps to prevent this “!Send/!Sync/futures” syndrom. Currently I have chosen to create a new connection to the database file for every request instead of sharing the same connection between Tokio tasks. I honestly don’t know if it is good or bad, currently I have no issue (I have very little traffic) but for mostly ergonomic reasons I didn’t want to have the DB connection in an axum State… Ideally I guess I should have some sort of pool that assigns one connection per thread, but I don’t think I will change this now (unless someone knows an easy way to do it…)
BTW I have a little database migration system for SQLite I’m really happy with — I mean, not overengineered and quite foolproof in my opinion. I can show you how I did it if you are interested.
No worries I like talking about code so I am happy with your comment. Yes I agree with you that I’m not sure what is the best way to handle the DB connection. Yeah sure please share the migration system I’m curious
having a thread-local rusqlite::Connection
would help but it would mean that (on tokio) that you still can’t hold the Connection
over an await point, since the task can get resumed on another thread at that point
I know! I meant: maybe I should have some sort of thread-local cache to keep at most one connection per thread (probably with a LocalKey<Option<Connection>>
that defaults to None I guess) since the multi thread Tokio runtime has a fixed number of worker threads.
sharing the same connection between Tokio tasks. […] Ideally I guess I should have some sort of pool that assigns one connection per thread
Why? These both just sound like ways to shoot yourself in the foot for essentially no reason.
If you don’t care about transactional behaviour anyway, then have actors mediating database interactions, but creating strange lifecycles and actively trying to step into the traps rusqlite tries to mitigate seems unnecessary.
Probably for the sake of overengineering! I don’t think I will change this soon in anyway. But it feels weird to use SQLite (mostly single-threaded) with Tokio (with async tasks distributed over async threads). I chose Tokio because the HTTP ecosystem is mostly async-bound in Rust.
sqlite is not single threaded tho? Do you mean synchronous?
I mean that typically, rusqlite::Transaction is !Send
and !Sync
.
That’s a transaction not a connection. It’s a convenience type to handle transactional constraints for you e.g. commit/rollback, but you can just manage that yourself on top of the connection (which is Send
). And it’s completely irrelevant if you don’t care about transactional semantics, you can just use the connection in autocommit mode.
And you can create multiple connections to the same sqlite database, and you should create multiple readonly connections to the same sqlite database.
This reminds me of the classic ikiwiki.
Ultimately, I have decided that I’m going to use Git forges as wikis, including my main public wiki. I feel the major downside is that people will not “take seriously” the content, but for the moment I refuse to set up an SSG or anything.
For my blog, I wrote 700-lines of Python, plus 400-lines of dual HTTP/Gemini server because I wanted something quite specific (being able to structure my Gemini capsule and the web version in different ways; RSS on web, gemfeed on Gemini, etc.). (And I deploy it in likely the worst way possible. But still, the content comes from Git too.)
But for everything else, the editing flow of modern Git forges is all the UI I need, and Markdown rendering is enough.
I respect your choice. For me the main difference is that the whole feedback loop is much shorter. No need to walk to my computer, preview the changes, and push etc. Instead just open my phone, write some text and click publish. Then I see the result and if I want to make changes it’s done in a few seconds. The sort of “hidden” cost of 1 minute here and there is in my experience very limiting. But I do respect your choice too. I understand there are tradeoffs. Just wanted to give my reasoning.
Oh, I’ve pushed changes to a Git forge using my phone :D
But yes, likely you can add a more streamlined interface if you don’t use a Git forge :D But you’d be surprised, editing on a Git forge is not great, but it’s also not as terrible as you would imagine.
(And honestly, I played with ikiwiki back in the day, and it has a web UI for posting, but I don’t know how well it works on small touch devices.)
(For short posts, I prefer ActivityPub. Although really, I’m questioning whether microblogging is a good idea at all.)
Although really, I’m questioning whether microblogging is a good idea at all.
Yes that is a very interesting discussion. On the one hand, the sort of holy grail in my eyes are well-written articles like E.W. Dijkstra’s letters. He used to write the letter by hand and usually they spanned multiple pages. So he would go very slowly and meticulously through the material and come with a well-thought out essay. On the other hand, sometimes I just want to remember a small trick or blog post like Simon Willison’s TIL posts: https://til.simonwillison.net/. Like if I’m programming and find a neat trick, then I think it’s fair to put that online somewhere so that other people and me can find it back (without paywall).
Oh, for both purposes I use Git forges as a wiki. I don’t really need to write those from a phone.
Also fx is a JSON TUI: https://fx.wtf