01
READY as a state boundary.
A new READY waits for earlier event tasks before Fjord replaces the server snapshot. Later events start only afterward, so old work cannot overwrite the new state.
Behind the scenes at Fjord
A bot in Rust. Our own graphics engine. Plus the frameworks, libraries and databases Fjord is built on.
Here we show what we develop ourselves and which technologies come together in Fjord.
Fjord
Fjord processes Discord events in order and runs independent tasks in parallel. Twilight connects the bot to Discord and keeps server data available locally. Dragonfly stores pending events and supports coordination of gateway connections.
01
A new READY waits for earlier event tasks before Fjord replaces the server snapshot. Later events start only afterward, so old work cannot overwrite the new state.
02
Events from the same server start in arrival order. Each waits for the preceding task to finish, so changes to that server cannot overtake one another.
03
The dispatcher separates tasks by key. Different servers can run at the same time; only tasks with the same key wait for one another.
04
The same message reaches AutoMod and the activity log at once. Each handles it separately for its own task.
05
Pending Discord events and their data are stored in Dragonfly. AutoMod and activity logs also use this shared store for temporary state. The bot still controls task execution.
06
When an enabled AutoMod filter matches, checking that message stops. Other filters do not trigger a second moderation response for the same event.
07
Twilight keeps servers, members, roles, channels, emojis, presences and voice states up to date in memory. Messages are not part of this cache.
08
Interactions are scheduled independently of server events. READY forms a state boundary within each gateway connection.
09
Dragonfly coordinates ownership of individual shards, or gateway connections. After a takeover, the former owner cannot claim or complete further events.
01 / Our own development
Fjell is our own graphics engine written in Rust. It combines backgrounds, avatars and text into personal welcome cards.
We wanted control over how these images are created. So we developed a solution tailored to Fjord that gives us creative freedom.
Cost efficiency matters just as much. Fjell delivers maximum performance without sacrificing quality while keeping CPU and memory use during generation as efficient as possible. This drastically reduces our server costs.
Our implementation reaches down to pixel processing. Custom SIMD loops use AVX2, FMA and BMI1/BMI2 to calculate multiple pixels in parallel.
Performance measurement
Four load levels with controlled card variations and the same test setup.
| Parallel | Cards/s | Cards/min | Render avg. | Render P50 | Render P95 | Render P99 | Total avg. | Total P50 | Total P95 | Total P99 | CPU avg. | RAM avg. |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 797,48 | 47.849 | 1,062 ms | 1,061 ms | 1,226 ms | 1,242 ms | 1,253 ms | 1,251 ms | 1,428 ms | 1,473 ms | 88,3 % | 381,2 MiB |
| 2 | 1.577,95 | 94.677 | 1,038 ms | 1,004 ms | 1,225 ms | 1,421 ms | 1,266 ms | 1,236 ms | 1,470 ms | 1,715 ms | 173,5 % | 360,1 MiB |
| 4 | 3.173,00 | 190.380 | 1,023 ms | 1,011 ms | 1,188 ms | 1,230 ms | 1,259 ms | 1,243 ms | 1,448 ms | 1,557 ms | 344,9 % | 375,3 MiB |
| 8 | 5.850,25 | 351.015 | 1,050 ms | 1,026 ms | 1,194 ms | 1,290 ms | 1,366 ms | 1,349 ms | 1,578 ms | 1,803 ms | 647,0 % | 385,8 MiB |
Measured throughput compared with perfect linear scaling.
| Workers | Measured | Ideal linear | Scaling | Efficiency |
|---|---|---|---|---|
| 1 | 797,48 | 797,48 | 1,00× | 100,0 % |
| 2 | 1.577,95 | 1.594,96 | 1,98× | 98,9 % |
| 4 | 3.173,00 | 3.189,92 | 3,98× | 99,5 % |
| 8 | 5.850,25 | 6.379,84 | 7,34× | 91,7 % |
All four local tests ran for 60 seconds each on an AMD Ryzen 9 9950X. They used 100 lightweight backgrounds with ordinary colours or illustrations and file sizes of about 100 to 300 KB, typically around 200 KB. The liquid layer remained disabled and the font stayed fixed; text and circle colours and their shader positions varied between cards.
Render time includes image generation plus PNG encoding and compression through completion of the final PNG. Network transfer and download time are not included.
The load generator used 1, 2, 4 or 8 parallel requests depending on the run. A new request began only after the previous PNG had been received completely and validated. The reported server CPU usage resulted under precisely this load. The graphics engine could distribute its server-side work across multiple cores.
* Internal measurements under the described conditions; not independently verified. They do not constitute a warranted characteristic, guarantee or performance commitment. Actual performance may vary by system, load and environment.
Aggressive random test
A much more variable setup with 1,000 backgrounds, 237 fonts and random effects for every request.
| Parallel | Cards/s | Cards/min | Render avg. | Render P50 | Render P95 | Render P99 | Total avg. | Total P50 | Total P95 | Total P99 | CPU avg. | RAM avg. |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 92,65 | 5.559 | 9,775 ms | 10,478 ms | 12,781 ms | 13,401 ms | 10,788 ms | 11,553 ms | 14,006 ms | 14,784 ms | 93,6 % | 1.205,6 MiB |
| 2 | 184,53 | 11.072 | 9,944 ms | 10,621 ms | 12,858 ms | 13,550 ms | 10,832 ms | 11,576 ms | 13,938 ms | 14,698 ms | 189,1 % | 1.278,8 MiB |
| 4 | 358,82 | 21.529 | 10,209 ms | 10,855 ms | 13,240 ms | 13,997 ms | 11,138 ms | 11,857 ms | 14,363 ms | 15,212 ms | 377,7 % | 1.300,9 MiB |
| 8 | 660,52 | 39.631 | 10,897 ms | 11,610 ms | 14,343 ms | 15,336 ms | 12,101 ms | 12,889 ms | 15,838 ms | 16,880 ms | 744,8 % | 1.308,6 MiB |
Measured throughput compared with perfect linear scaling.
| Workers | Measured | Ideal linear | Scaling | Efficiency |
|---|---|---|---|---|
| 1 | 92,65 | 92,65 | 1,00× | 100,0 % |
| 2 | 184,53 | 185,30 | 1,99× | 99,6 % |
| 4 | 358,82 | 370,60 | 3,87× | 96,8 % |
| 8 | 660,52 | 741,20 | 7,13× | 89,1 % |
These four local tests ran for 60 seconds each on the same AMD Ryzen 9 9950X. Every request selected from 1,000 more demanding backgrounds sized from 800 KB to 2.4 MB and from 237 fonts. Text, transparency, font and avatar sizes, outline, text and circle colours, and shader angle, strength and intensity were varied. About half of the cards also enabled the liquid layer with random colour, opacity and blur.
The load generator used 1, 2, 4 or 8 parallel workers in a closed loop. Each worker started its next request only after the previous PNG had been received completely and validated. Every 60-second run completed without errors, timeouts or invalid PNGs.
Render time includes image generation plus PNG encoding and compression through completion of the final PNG. Network transfer and download time are not included.
* Internal measurements under the described conditions; not independently verified. They do not constitute a warranted characteristic, guarantee or performance commitment. Actual performance may vary by system, load and environment.
02 / Our technical foundation
Alongside our own engine, we use Rust, Leptos, TypeScript, Vue, Twilight, Dragonfly, PostgreSQL, ScyllaDB and RustFS. Each technology has a clear role in the system.
Programming language
Rust powers our Discord bot, backend, card editor and Fjell graphics engine.
Logo © Rust Foundation. CC BY 4.0 · unmodified
Web framework
We use Leptos for parts of our web interface. The framework brings Rust to the browser and fits naturally into the rest of our stack.
Logo by the Leptos maintainers. MIT · unmodified
Programming language
We write the interactive public pages in TypeScript. Type checking helps us keep components and state consistent.
Official TypeScript logo. Used under the TypeScript branding guidelines.
Web framework
Vue powers the components of our public website, from navigation and documentation to other interactive areas. It helps us keep those interfaces cohesive and extensible.
Logo © Evan You. CC BY-NC-SA 4.0 · unmodified
Library for Discord
We use Twilight to connect to Discord. The library links our bot written in Rust to Discord.
Logo by Fezhoof. CC BY-SA 4.0 · unmodified
Database
Dragonfly is our shared temporary data store for Discord events, coordination of shards and multiple gateway connections, AutoMod and activity logs.
Software under BSL 1.1 with an additional use grant.
Relational database
PostgreSQL complements our data layer for relational data and structures. It runs alongside ScyllaDB as a separate part of our infrastructure.
Database
ScyllaDB is one part of our data layer alongside PostgreSQL. We use the two systems for different jobs within Fjord.
Object storage
We use RustFS for S3-compatible object storage. It adds a separate storage layer alongside PostgreSQL and ScyllaDB.
Software under Apache 2.0. RustFS is a trademark of RustFS, Inc.