Boty Discord

Cztery boty produkcyjne obsługujące serwery naszych marek. Ticketowanie z pingiem zespołu, powitania nowych członków, weryfikacja adresów e-mail i porządkowanie ról - wszystko dopasowane do konkretnego serwera. Odciążają obsługę i pilnują higieny społeczności bez ręcznej roboty.

Boty Discord
TL;DR

Cztery boty produkcyjne, każdy dopasowany do konkretnego serwera: ticketowanie z pingiem właściwego zespołu, powitania i onboarding, weryfikacja e-mail przy wejściu, porządkowanie ról. Wszystkie stoją na jednym rdzeniu i architekturze cogów, więc każdy serwer bierze tylko te funkcje, których naprawdę potrzebuje. Nowa funkcja to nowy cog, nie kolejny if w monolicie.

Wprowadzenie

Społeczności naszych marek żyją na Discordzie, a nie na stronie. To tam trafia nowy klient, tam otwiera zgłoszenie, tam czeka na rolę dającą dostęp do właściwych kanałów. Przy kilkuset członkach ręczne ogarnianie ticketów, powitań i ról po prostu przestaje się spinać - ktoś musi być na miejscu, patrzeć i klikać, a to nie skaluje się z liczbą osób.

Zamiast pisać jednego uniwersalnego bota do wszystkiego, zbudowaliśmy jeden rdzeń i zestaw modułów, z których składa się każdego bota osobno. Cztery serwery, cztery role, cztery konfiguracje - ale jedno miejsce, w którym żyje logika. Ten case study jest o tym, dlaczego taki podział opłacał się bardziej niż wygodny na początku monolit.

Dlaczego nie jeden bot do wszystkiego

Kuszące jest napisać jednego bota, który robi całą robotę na wszystkich serwerach. Problem w tym, że każdy serwer ma trochę inne potrzeby: inny zespół do pingu przy tickecie, inną ścieżkę wejścia nowego członka, inne role i inny próg weryfikacji. Uniwersalny bot, który ma obsłużyć je wszystkie, z czasem robi się choinką z flag, w której nikt nie chce niczego ruszać, bo nie wiadomo, co jeszcze od tego zależy.

Druga pułapka to współdzielony stan. Jeden proces obsługujący cztery serwery naraz to jeden punkt awarii - błąd w logice ticketów potrafi położyć powitania na zupełnie innym serwerze. A im więcej serwer wozi kodu, którego nie używa, tym trudniej cokolwiek w nim bezpiecznie zmienić.

Jeden rdzeń, wiele cogów

Poszliśmy w drugą stronę: jeden rdzeń z modułami, które w ekosystemie Discorda nazywają się cogami, a każdy bot to zestaw włączonych cogów. Serwer ticketowy bierze cog ticketów, serwer, który tego nie potrzebuje, po prostu go nie włącza.

Monolit kontra rdzeń z cogami

AspektJeden bot do wszystkiegoRdzeń z cogami
Nowa funkcjakolejny if w środkunowy, odizolowany cog
Serwer bez danej funkcjii tak wozi jej kodpo prostu jej nie włącza
Awaria jednego modułuryzyko dla całościograniczona do cogu
Poprawka logikiszukanie w monoliciejedno miejsce, wszędzie gdzie cog włączony

Cztery boty, cztery role

W praktyce ekosystem to cztery odrębne boty, z których każdy robi jedną rzecz porządnie. Ticketowy otwiera wątki zgłoszeń i pinguje właściwy zespół, żeby zgłoszenie nie utknęło w próżni. Powitalny prowadzi nowego członka przez pierwsze kroki. Weryfikacyjny potwierdza adres e-mail przy wejściu. Porządkowy pilnuje higieny ról i przydziela je automatycznie.

Ten podział nie jest kosmetyczny. Każdy bot ma własny zakres uprawnień i własny stan, więc awaria jednego nie pociąga reszty, a zmiana w jednym nie wymaga myślenia o trzech pozostałych. Wspólny jest tylko rdzeń - to, jak cog wpina się do bota, jak czyta konfigurację i jak gada z API.

Cztery boty, cztery role

BotCo robiKluczowy cog
Ticketowyotwiera wątki zgłoszeń i pinguje właściwy zespółtickets
Powitalnyonboarding i pierwsze kroki nowego członkawelcome
Weryfikacyjnypotwierdzenie adresu e-mail przy wejściumailcheck
Porządkowyautomatyczne przydzielanie i higiena rólroles

Jak wygląda cog

Cog to zamknięta jednostka: własne komendy, własne nasłuchy, własny stan. Wpinasz go do bota jedną linią, wypinasz tak samo. Nie ma globalnego splątania - cog ticketów nie wie nic o cogu ról i nie musi. Poniżej wycinek weryfikacji: nowy członek dostaje rolę oczekującego i prompt do potwierdzenia adresu, zanim zobaczy resztę serwera.

verify.py · python
class VerifyCog(commands.Cog):
    def __init__(self, bot):
        self.bot = bot

    @commands.Cog.listener()
    async def on_member_join(self, member):
        pendingRole = member.guild.get_role(self.pendingRoleId)
        await member.add_roles(pendingRole)
        await self.sendVerifyPrompt(member)

Nazwy takie jak on_member_join czy add_roles narzuca API Discorda i zostają jak są - reszta identyfikatorów idzie po naszej konwencji. To granica, na której idziesz za biblioteką, a nie za własnym stylem, i jedyne miejsce, gdzie mieszają się dwie konwencje nazewnicze.

i
Informacja

Weryfikacja e-mail przy wejściu to nie ozdoba. Najtańsza obrona przed falą fake-kont to postawienie progu, który boty rejestrujące masowo muszą przejść - potwierdzenie realnego adresu odsiewa większość z nich, zanim w ogóle zobaczą kanały. Rola oczekującego trzyma nowego członka za drzwiami do momentu potwierdzenia.

Co zostaje po stronie utrzymania

Największy zysk nie jest widoczny na serwerze, tylko w tym, jak się te boty utrzymuje. Poprawka w logice ticketów idzie w jednym miejscu i trafia wszędzie tam, gdzie ten cog jest włączony - nie przepisujesz jej cztery razy i nie zapominasz o jednym serwerze. Żaden serwer nie wozi kodu, którego nie używa, więc jego konfiguracja jest dokładnie tak złożona, jak jego realne potrzeby.

4
boty produkcyjne
1
wspólny rdzeń zamiast czterech osobnych
n
cogów włączanych per serwer

Dorzucenie piątego serwera nie oznacza pisania piątego bota od zera. Składa się go z tego, co już jest: bierzesz cogi, które pasują, ustawiasz konfigurację i tyle. To jest różnica między czterema osobnymi projektami a jednym ekosystemem, który rośnie przez dokładanie modułów, a nie przez mnożenie kodu.

Więcej projektów

Inne realizacje z tej samej kategorii - zobacz, jak podchodzimy do podobnych wyzwań.

Masz podobny projekt?

Napisz do nas - wycena jest bezpłatna i wraca w godzinę.