Tady

Հրապարակային Discord-բոտ սերվերների համար՝ 2500+ սերվեր և 260 000+ օգտատեր գագաթնակետին։ Շարդերի սեփական մենեջեր PHP-ով, Redis ակտիվ վիճակի համար, ինտերֆեյս երկու լեզվով։

Ժամանակահատված
2021 թ․ օգոստոս — մինչ օրս
Կարգավիճակ
Ակտիվ
Իմ դերը
Միակ մշակողը՝ գաղափարը, ճարտարապետությունը, սերվերային տրամաբանությունը, մասշտաբավորումը և հետագա զարգացումը։
Tady-ի պաստառը՝ բազմալեզու Discord-բոտ՝ գործիքներ, խաղարկություններ, մոդերացիա

Տեխնոլոգիաներ

  • PHP
  • DiscordPHP
  • MySQL
  • Redis
  • JavaScript
  • discord.js
  • Node.js

Խնդիրը

Discord-ի համայնքներում, որտեղ ես շփվում էի, պարբերաբար պակասում էին նույն գործառույթները՝ մասնակիցներին պատահականորեն թիմերի բաժանել, ստեղծել հաշվիչ ալիքներ, ռուսերենով խաղարկություններ անցկացնել անհրաժեշտ պայմաններով և սերվերն ավելի հարմար մոդերացնել։ Առկա բոտերը լուծում էին միայն առանձին խնդիրներ, իսկ ամբողջ անհրաժեշտ հավաքածուն նույնիսկ մի քանի լուծումից հավաքել չէր ստացվում։ Այդ պատճառով Tady-ն սկսվեց որպես մի քանի Discord-սերվերի համար նախատեսված մասնավոր բոտ։

Լուծումը

Երբ պարզ դարձավ, որ նույն սցենարներն անհրաժեշտ են նաև այլ համայնքների, բոտը դարձավ հրապարակային։ Բոտն արագ հավաքեց հարյուր սերվեր, իսկ այդ շեմից սկսած Discord-ը պահանջում է պարտադիր վավերացում։ Առանձին գործընթաց էր արտոնյալ intent-ների ստուգումը, առանց որոնց հրամանների մի մասը չի աշխատում։ Նախագծի աճին զուգընթաց ես ճարտարապետությունը հարմարեցրի մասշտաբին՝ շարդավորում, Redis ակտիվ վիճակի համար և բազմալեզու ինտերֆեյս։

Ճարտարապետություն

Tady-ի շարդավորումը և վիճակըՇարդն ինքնին Gateway-ի առանձին միացում է. սերվերները (Discord API-ում՝ guild-ները) դրան ամրագրվում են իրենց ID-ից բխող բանաձևով, և մեկ շարդը սպասարկում է առավելագույնը 2500 սերվեր։ Tady-ում յուրաքանչյուր շարդ գործարկվում է առանձին PHP-պրոցեսում. DiscordPHP-ն պրոցեսների մենեջեր չի տրամադրում, ուստի դրանք գործարկում, վերահսկում և վերագործարկում է նախագծի սեփական մենեջերը։ Վիճակը մնում է ընդհանուր. Redis-ը պահում է ընթացող խաղարկությունները և դրանց ժամաչափերը, իսկ MySQL-ը տվյալների հիմնական աղբյուրն է, և դրա տվյալները պահպանվում են վերագործարկումից հետո։յուրաքանչյուրն իր միացումընոր խաղարկությունը՝ միանգամից երկուսումմեկնարկի ժամանակDiscord Gatewayշարդը Gateway-ի միացում է, ոչ թե պրոցեսսերվեր → շարդ՝ (guild_id >> 22) % num_shardsմեկ շարդը՝ առավելագույնը 2500 սերվեր, դրանից ավելիի դեպքում շարդավորումը պարտադիր էTady — PHP / DiscordPHPՇարդերի սեփական մենեջերգործարկում, վերահսկում, վերագործարկումShard 0պրոցեսShard 1պրոցես…պրոցեսShard NպրոցեսԸնդհանուր վիճակRedisընթացող խաղարկություններ և ժամաչափերMySQLտվյալների հիմնական աղբյուր, տվյալները պահպանվում են վերագործարկումից հետո
Շարդն ինքնին Gateway-ի առանձին միացում է. սերվերները (Discord API-ում՝ guild-ները) դրան ամրագրվում են իրենց ID-ից բխող բանաձևով, և մեկ շարդը սպասարկում է առավելագույնը 2500 սերվեր։ Tady-ում յուրաքանչյուր շարդ գործարկվում է առանձին PHP-պրոցեսում. DiscordPHP-ն պրոցեսների մենեջեր չի տրամադրում, ուստի դրանք գործարկում, վերահսկում և վերագործարկում է նախագծի սեփական մենեջերը։ Վիճակը մնում է ընդհանուր. Redis-ը պահում է ընթացող խաղարկությունները և դրանց ժամաչափերը, իսկ MySQL-ը տվյալների հիմնական աղբյուրն է, և դրա տվյալները պահպանվում են վերագործարկումից հետո։

Հիմնական տեխնիկական որոշումները

  • Շարդերի մենեջեր. Discord-ի հետ միացումը բաժանված է մի քանի Gateway-միացումների, և դրանցից յուրաքանչյուրն աշխատում է առանձին PHP-պրոցեսում։ DiscordPHP-ն ընդունում է շարդի համարը, բայց պրոցեսները չի կառավարում, ուստի նախագծում իրականացված է դրանց գործարկման, վերահսկման և վերագործարկման սեփական մենեջեր։
  • Redis-ը՝ որպես ակտիվ վիճակի շերտ, բազան՝ որպես տվյալների հիմնական աղբյուր. վերագործարկման ժամանակ բոտը վիճակը վերականգնում է բազայից, իսկ նոր խաղարկությունները գրում է միանգամից երկու տեղ։
  • Լեզուն վերցվում է հենց օգտատիրոջ Discord-ի կարգավորումներից, անգլերենը՝ պահեստային տարբերակ. ռուսալեզու լսարանով սերվերում ոչ ոք ստիպված չէ լեզուն ձեռքով փոխել։
  • Սխալների մշակումը տարբերակում է խնդրի աղբյուրը՝ իրավունքը պակասում է օգտատիրոջը, թե բոտին, իսկ իրավունքի անվանումը ցուցադրվում է հրամանը կանչողի լեզվով։
  • Արտոնյալ intent-ները կրճատվել են մինչև անհրաժեշտը. վավերացման ժամանակ հայցվել էին բոլոր երեքը, բայց Presence-ն այլևս պետք չէ, և ընթացիկ ստուգման մեջ մնում են միայն Members-ը և Message Content-ը։

Մասշտաբ և շարդավորում

Երբ բոտն աճեց մինչև 2500+ սերվեր, նախագիծն անցավ Discord-ի շարդավորման, որն այդ մասշտաբում պարտադիր է։

Discord-ում շարդը Gateway-ի առանձին միացում է։ Սերվերները (Discord API-ում՝ guild-ները) շարդերի միջև բաշխվում են իրենց ID-ից բխող բանաձևով, ընդ որում մեկ շարդը սպասարկում է առավելագույնը 2500 սերվեր։ DiscordPHP-ն ընդունում է շարդավորման պարամետրերը, բայց շարդ-պրոցեսների պատրաստի մենեջեր չի տրամադրում, ուստի Tady-ի համար իրականացվեց սեփականը. յուրաքանչյուր շարդ աշխատում էր առանձին PHP-պրոցեսում, իսկ գործարկումը, վերահսկումը և վերագործարկումն ավտոմատացված էին։ Պրոցեսների միջև վիճակը մնում էր ընդհանուր. Redis-ը պահում էր ակտիվ խաղարկությունները և ժամաչափերը, իսկ MySQL-ը ծառայում էր որպես տվյալների հիմնական աղբյուր և պահպանում էր մշտական վիճակը։ Շարդ-պրոցեսի վերագործարկման ժամանակ ակտիվ վիճակը չէր կորչում, այլ վերականգնվում էր MySQL-ից Redis-ում՝ խաղարկությունները, LFG-ն, հաշվիչ ալիքները և պահպանվող մյուս սցենարները։

Նախագծի զարգացման ընթացքում իրականացվել է առանձին տարբերակ Node.js-ով և discord.js-ով։ Հետագայում այդ ճյուղի զարգացումը դադարեցվել է, իսկ ընթացիկ production-ը մնացել է PHP-ի և DiscordPHP-ի վրա։

Բազմալեզվություն

Բոտն աջակցում է ռուսերեն և անգլերեն։ Պատասխանները, կոճակների մակագրություններն ու օգնության հաղորդագրություններն ավտոմատ հարմարվում են այն լեզվին, որն օգտատերն ընտրել է Discord-ի ինտերֆեյսում։ Եթե ընտրված լեզուն չի աջակցվում, լռելյայն օգտագործվում է անգլերենը։

Բազմալեզվություն
Նույն /help-ը ռուսերեն և անգլերեն. կատեգորիաները, հրամանների ցանկը և հաշվիչները հետևում են Discord-ում օգտատիրոջ ընտրած լեզվին։

Սխալների մշակում

Բոտը տարբերակում է մերժման պատճառները և յուրաքանչյուրին պատասխանում է յուրովի։ Եթե իրավունք է պակասում, այն ստուգում է՝ պակասում է օգտատիրոջը, թե հենց բոտին, և իրավունքն անվանում է հրամանը կանչողի լեզվով։ Առանձին են մշակվում իրավունքների հետ կապ չունեցող դեպքերը՝ մասնակցի դերն ավելի բարձր է, ադմինիստրատորին հնարավոր չէ լռեցնել։ Յուրաքանչյուր պատասխան նշում է պատճառը և, որտեղ հնարավոր է, հաջորդ քայլը, իսկ եթե պարզել չհաջողվեց, հաղորդագրությունից կարելի է անմիջապես անցնել աջակցության սերվեր։

Սխալների մշակում՝ մերժման չորս տեսակ
Մերժման չորս տեսակ. իրավունքը պակասում է օգտատիրոջը. իրավունքը պակասում է բոտին՝ այն միացնելու և կրկնելու հուշումով. մասնակցի դերը հավասար է կամ բարձր է հրամանը կանչողի դերից. ադմինիստրատորին հնարավոր չէ լռեցնել։ Պատասխանը տեսնում է միայն հրամանը կանչողը։

Տևողության ձևաչափ

Տևողությունը տրվում է տեքստով՝ առանց ձեռքով վայրկյանների կամ րոպեների վերածելու։ Օրինակ՝ 1d 3h 12m 10s գրառումը ճիշտ մեկնաբանվում է որպես 1 օր, 3 ժամ, 12 րոպե և 10 վայրկյան։ Այս ձևաչափն աշխատում է բոլոր այն հրամաններում, որտեղ պետք է նշել ժամկետ։

Տևողության ձևաչափ
/mute-ի օգնությունը՝ հրամանի շարահյուսությունը, տևողության ձևաչափը «1d 3h 12m 10s» և երկու պատրաստի օրինակ։ Պատասխանը տեսնում է միայն հրամանը կանչողը։

Խաղարկություններ

/giveaway հրամանը գործարկում է խաղարկություն, որն ինքն է ավարտվում ժամաչափով։ Տևողությունը տրվում է նույն ձևաչափով, ինչ մյուս հրամաններում։ Գործարկումից հետո բոտը հետևում է մնացած ժամանակին, ավտոմատ ամփոփում է արդյունքները և մասնակիցներից պատահականորեն ընտրում մեկ կամ մի քանի հաղթող։ Խաղարկության հեղինակը կարող է դիտել իր ընթացիկ խաղարկությունները, ավարտել դրանք ժամկետից շուտ և անհրաժեշտության դեպքում վերընտրել հաղթողներին։

Խաղարկություններ
2022 թվականի բնօրինակ սքրինշոթ՝ բոտի ռուսերեն ինտերֆեյսով։ Հայտարարության մեջ նշված են կազմակերպիչը, մրցանակը և հովանավորը, հաղթողների թիվը և ամփոփման ժամկետը. ժամաչափով բոտն ամփոփում է՝ չորս հաղթող և 3237 մասնակից։ Հաշվիչը ցույց է տալիս 3286, քանի որ կադրն արվել է ամփոփումից մեկ ամիս անց և ռեակցիաները շարունակել են ավելանալ։ Արդյունքը ֆիքսվում է ամփոփման պահին և հաշվիչից չի կարդացվում. այնտեղ միշտ կա մեկ ավելորդ ռեակցիա՝ բոտինը։

Օգնություն և հուշումներ

Յուրաքանչյուր հրաման ունի կարճ նկարագրություն, հրահանգ և օրինակներ. դրանք կարելի է տեսնել /help-ով (հրամանների ցանկ) կամ /help <հրամանի անվանում>-ով (մանրամասներ կոնկրետ հրամանի մասին)։ Այդ պատասխանը տեսանելի է միայն նրան, ով հարցրել է, և ալիքում ավելորդ հաղորդագրություններ չի թողնում։

Օգնություն և հուշումներ
/help-ը թվարկում է հրամաններն ըստ կատեգորիաների, իսկ /help <հրաման>-ը բացում է մեկը։ Այստեղ՝ giveaway՝ create, list, delete, reroll ենթահրամաններով և օրինակներով։

Աջակցության սերվեր

Բոտն ունի աջակցության սերվեր, որտեղ օգտատերերն օգնություն են ստանում, գտնում հաճախակի տրվող հարցերի պատասխանները և հետևում նախագծի նորություններին։ Բոտը երբեք զանգվածային հաղորդագրություններ չի ուղարկում օգտատերերի անձնական հաղորդագրություններում կամ սերվերներում։

Աջակցության սերվեր
Աջակցության սերվերի նորությունների ալիքը. յուրաքանչյուր հայտարարություն դուրս է գալիս միանգամից երկու լեզվով, իսկ կողային վահանակում պահվում են սերվերների, օգտատերերի և անդամների կենդանի հաշվիչները։

Օժանդակ և զվարճալի հրամաններ

Հիմնական սցենարներից բացի Tady-ն ունի փոքր հրամաններ համայնքի առօրյայի համար. /teams-ը մասնակիցներին պատահականորեն բաժանում է թիմերի, /translit-ը մականունների համար կիրիլիցան վերածում է լատինատառի, /info-ն և /avatar-ը ցույց են տալիս հաշվի տվյալները, իսկ /counter-ը ստեղծում է հաշվիչ ալիքներ։ Առանձին կանգնած է /lfg-ը՝ խաղընկերների հավաքը. բոտը հրապարակում է գրառում՝ տեղերով և ժամանակով, մասնակիցները միանում են կոճակով, իսկ երբ խումբը լրանում է, բոտն ինքն է դա հայտարարում։

Օժանդակ և զվարճալի հրամաններ
Հինգ հրաման. /teams-ը բաժանում է թիմերի, /info-ն ցույց է տալիս հաշվի և սերվեր մտնելու ամսաթվերը, /avatar-ը բերում է ավատարը, /lfg-ն հավաքում է խումբ խաղի համար՝ տեղերով, ժամկետով և կոճակներով, /translit-ը կիրիլիցան դարձնում է լատինատառ։

Արդյունքներ

  • Անցել է Discord-ի վավերացումը և արտոնյալ intent-ների ստուգումը, առանց որոնց հրամանները չեն աշխատում մեծ թվով սերվերներում։
  • Մի քանի համայնքի համար նախատեսված մասնավոր բոտից վերաճել է հրապարակային նախագծի, որը մինչ օրս աշխատում և սպասարկվում է։
  • Շարդավորումը և ընդհանուր վիճակը թույլ տվեցին մասշտաբավորել բոտը՝ առանց ամբողջ բեռը մեկ Gateway-միացման կամ պրոցեսի կապելու։

Մետրիկաներ

Discord-սերվեր գագաթնակետին
2500+
օգտատեր գագաթնակետին
260 000+

Փաստեր

  • Discord-ի աջակցության հայտերի համակարգում սխալի պատճառով վավերացումը տևեց 4 ամիս, և այդ ամբողջ ընթացքում հարթակը թույլ չէր տալիս օգտատերերին բոտը հրավիրել իրենց սերվերներ։