Dispatcher
Routes incoming Telegram updates to appropriate handlers. Configurable max goroutines (default: 200) with enhanced error handling and panic recovery.
Alita Robot is a modern Telegram group management bot built with Go and the gotgbot library. This document provides an overview of the architectural decisions, technology stack, and design principles that guide the codebase.
| Component | Technology | Purpose |
|---|---|---|
| Language | Go 1.26+ | Core application runtime |
| Telegram Library | gotgbot v2 | Telegram Bot API wrapper |
| Build System | GoReleaser | Multi-platform builds and releases |
| Component | Technology | Purpose |
|---|---|---|
| Database | PostgreSQL | Persistent data storage |
| ORM | GORM | Object-relational mapping |
| Migrations | Custom Engine | Schema versioning with transactional execution |
The database uses a surrogate key pattern: auto-increment id as PK with external IDs (user_id, chat_id) as unique constraints.
| Component | Technology | Purpose |
|---|---|---|
| Caching | Redis | Distributed caching layer |
| Client | gocache | Go cache library with marshaling |
| Stampede Protection | singleflight | Prevents thundering herd on cache misses |
All cache keys are prefixed with alita: for namespace isolation. TTLs range from 20 seconds (anonymous admin verification) to 1 hour (language preferences).
| Component | Technology | Purpose |
|---|---|---|
| Metrics | Prometheus | Metrics and observability |
| Tracing | OpenTelemetry | Distributed tracing with OTLP/console exporters |
| Health | HTTP /health | Unified health, metrics, pprof on single port |
Dispatcher
Routes incoming Telegram updates to appropriate handlers. Configurable max goroutines (default: 200) with enhanced error handling and panic recovery.
Module System
Feature modules in alita/modules/ follow a consistent pattern: moduleStruct, handler methods, LoadModule registration. Help module loads last to collect all commands.
Cache Layer
Redis caching with singleflight stampede protection. Per-type TTLs, automatic invalidation on writes, and distributed cache with namespace isolation.
Permission System
Centralized permission validation in alita/utils/chat_status/. Checks are cached to reduce Telegram API calls. Supports anonymous admin detection.
Monitoring
4-tier auto-remediation, activity tracking (per-chat and per-user DAU/WAU/MAU), background stats every 30s, and GC triggers on memory thresholds.
Graceful Shutdown
Central coordinator with LIFO handler execution. Each handler gets panic recovery. Total timeout: 60 seconds.
All database operations are organized by domain in alita/db/{domain}/repository.go files (e.g., alita/db/bans/repository.go, alita/db/filters/repository.go). Each package provides Get/Add/Update/Delete functions for its domain, with surrogate key pattern (auto-increment id as PK, external IDs as unique constraints):
// Example: Direct domain function callssettings := db.GetChatSettings(chatId)db.UpdateChatSettings(chatId, newSettings)Middleware functionality is implemented through decorators in alita/utils/helpers/decorators.go. Common cross-cutting concerns are handled uniformly:
Concurrent processing uses bounded worker pools with panic recovery:
DISPATCHER_MAX_ROUTINES)Redis-based caching with stampede protection:
+------------------+ | Telegram | | Bot API | +--------+---------+ | +------------------+------------------+ | | Webhook Mode Polling Mode | | v v +----------+----------+ +-----------+-----------+ | HTTP Server | | Updater | | /webhook/{secret} | | GetUpdates loop | +----------+----------+ +-----------+-----------+ | | +------------------+------------------+ | v +----------+----------+ | Dispatcher | | (configurable routines)| +----------+----------+ | +-------------------+-------------------+ | | | v v v +------+------+ +------+------+ +------+------+ | Handler | | Handler | | Handler | | (Command) | | (Callback) | | (Message) | +------+------+ +------+------+ +------+------+ | | | +-------------------+-------------------+ | +--------------+--------------+ | | v v +---------+----------+ +---------+----------+ | Redis Cache | | PostgreSQL | | (cache lookup) | | (via GORM) | +--------------------+ +--------------------+The dispatcher routes incoming Telegram updates to appropriate handlers:
dispatcher := ext.NewDispatcher(&ext.DispatcherOpts{ Error: func(b *gotgbot.Bot, ctx *ext.Context, err error) ext.DispatcherAction { // Error handling with structured logging return ext.DispatcherActionNoop }, MaxRoutines: config.AppConfig.DispatcherMaxRoutines,})Each feature module follows a consistent pattern:
moduleStruct with module nameLoadModule functioninit() via RegisterLegacyModule(name, priority, loadFunc) or RegisterModule(m Module)modules.LoadAllModules(dispatcher) in priority orderRedis caching with stampede protection:
alita: for namespace isolationComprehensive monitoring subsystems:
// Dispatcher limits concurrent handler executionMaxRoutines: 200 // Configurable via DISPATCHER_MAX_ROUTINES
// Worker pools use bounded parallelismchatWorkers := make(chan struct{}, config.AppConfig.ChatValidationWorkers) // CHAT_VALIDATION_WORKERSdbWorkers := make(chan struct{}, config.AppConfig.DatabaseWorkers) // DATABASE_WORKERSmsgWorkers := make(chan struct{}, config.AppConfig.MessagePipelineWorkers) // MESSAGE_PIPELINE_WORKERSbulkWorkers := make(chan struct{}, config.AppConfig.BulkOperationWorkers) // BULK_OPERATION_WORKERScacheWorkers := make(chan struct{}, config.AppConfig.CacheWorkers) // CACHE_WORKERSstatsWorkers := make(chan struct{}, config.AppConfig.StatsCollectionWorkers) // STATS_COLLECTION_WORKERS// Prevents multiple goroutines from rebuilding same cache entryvar cacheGroup singleflight.Group
// 30-second timeout with automatic cleanupresultCh := cacheGroup.DoChan(cacheKey, func() (any, error) { return loadFromDatabase()})
select {case res := <-resultCh: result = res.Val err = res.Errcase <-time.After(30 * time.Second): cacheGroup.Forget(cacheKey) // Prevent goroutine accumulation err = errors.New("cache load timeout")}// Shutdown manager coordinates cleanup in ordershutdownManager := shutdown.NewManager()shutdownManager.RegisterHandler(func() error { // Cleanup monitoring, database, cache return nil})Alita uses a 4-layer error handling hierarchy:
Error: func(b *gotgbot.Bot, ctx *ext.Context, err error) ext.DispatcherAction { defer error_handling.RecoverFromPanic("DispatcherErrorHandler", "Main") // Log error with structured fields return ext.DispatcherActionNoop}Worker pools implement panic recovery:
go func() { defer func() { if r := recover(); r != nil { log.WithField("panic", r).Error("Panic in worker") } }() // Worker logic}()Individual handlers use decorators for error handling:
// Permission checks return early on failureif !chat_status.RequireUserAdmin(b, ctx, nil, user.Id, false) { return ext.EndGroups}Command decorators provide permission validation and error context:
// Decorators wrap handlers with cross-cutting concernshelpers.MultiCommand(dispatcher, []string{"cmd", "alias"}, handler)The database uses a surrogate key pattern:
id field (internal identifier)user_id and chat_id with unique constraints