Show HN: I wrote a new BitTorrent tracker in Elixir (github.com)
I'm currently in a journey to learn and improve my Elixir and Go skills (my daily job uses C++) and looking through my backlog for projects to take on I decided Elixir is the perfect language to write a highly-parallel BitTorrent tracker. So I have spent my free time these last 3 months writing one! Now I think it has enough features to present it to the world (and a docker image to give it a quick try).
I know some people see trackers as relics of the past now that DHT and PEX are common but I think they still serve a purpose in today's Internet (purely talking about public trackers). That said there is not a lot going on in terms of new developments since everyone just throws opentracker in a vps a calls it a day (honorable exceptions: aquatic and torrust).
I plan to continue development for the foreseeable future and add some (optional) esoteric features along the way so if anyone currently operates a tracker please give a try and enjoy the lack of crashes.
note: only swarm_printout.ex has been vibe coded, the rest has all been written by hand.
78 comments
[ 1.4 ms ] story [ 151 ms ] thread[0] https://hexdocs.pm/logger/1.18.4/Logger.html [1] https://hexdocs.pm/telemetry/readme.html
The let it crash philosophy allows you to ignore most corner cases with the knowledge that, if they are encountered or a cosmic ray flips a bit, the crash is localised to a single client. I have worked with Elixir almost a decade at this point, and I have never seen an unexpected downtime of the apps I deployed. Aside of maintenance and updates, they all have 100% uptime. How cool is that?
This is how I sell it to clients. “Will you be using Python, Go?” Me: “What about Elixir and the promise that your service won’t ever crash? And you get cool dashboards with it.” Them: “Sold.”
I wish there was a systems language that allows you to pattern match on structs and enums, and in function signatures like Elixir
This is such a dangerous take. Also Elixir is not strongly typed, so...
And Elixir is strongly typed by most definitions. Perhaps you mean static?
The fact that you recall a single instance of crashing software says a lot about the quality assurance of the BEAM.
[1] https://docs.inko-lang.org/manual/latest/getting-started/pat...
I wrote a basic tracker in Elixir a few years ago, here's the code: https://github.com/aalin/mr_torrent
Also my console gets spammed with:
04:43:20.160 [warning] invalid 'event' parameter: size: 6 value: "paused"
but it seems to work. I would've liked to see HTTP stats too but I guess UDP is fine (though I have it disabled)
Ah, missed that.
However I decided to just use redis as the DB. It sounds like your entire DB is in memory? Any interesting design decisions you made and/or problems faced in doing so?
(My redis solution isn't great since it does not randomize peers in subsequent announces afaik)
You might be able to get the slot count from eta:table_info(Table, stats), although that's not intended for production use, so the format may change without notice.
If the author wishes to learn how to design services in Elixir, or any BEAM language, with OTP, they can take a look at "Designing Elixir Systems with OTP" by by James Edward Gray and Bruce Tate, and "Functional Web Development with Elixir, OTP, and Phoenix" by Lance Halvorsen.
OTP stands for Open Telecom Platform, although it's not that much about telecom anymore (it's more about software that has the property of telecom applications, but yeah.) If half of Erlang's greatness comes from its concurrency and distribution and the other half comes from its error handling capabilities, then the OTP framework is the third half of it.
https://learnyousomeerlang.com/what-is-otp
ETS is built into OTP, so how is using ETS not "OTP-first"? What's wrong with using ETS? It's just an in-memory store.
I looked through the code and didn't find it to be anywhere close to procedural in style.
There may be cool cases for extra GenServers or gen_statems but a lot of uses of Elixir and Phoenix don't warrant making any fancy architectural choices. Partly because the runtime is already fancy for you.
- https://en.m.wikipedia.org/wiki/Peer_exchange
If you get and keep a list of bootstrap nodes when you find one, then you can random select from the bootstrap addresses rather than all routable IPv4 addresses.
You'd need to probe v4 space through NAT64 and exchange v6 addresses after that, or include a cache of viable v6 addresses with clients. That gets you close to centralized service again, because how do you get the viable addresses to distribute with the client? Probably by running a supernode and dumping the list of supernodes into the client source every so often; but starting off with just that node listed.
There could other ways, embedding them on SRV DNS records, etc. It's the same issue as with getting a DNS server. You could in theory get addresses of bootstrap nodes from your ISP through DHCP (lol, sure).
after seeing this i saw that same mindset. not flashing any big genservers. simplified with fast procs, raw ETS tables. simple flow, but still fault aware. still clean.