(new): expand runtime APIs
Golang lint / lint (push) Successful in 58s
Golang lint / lint (pull_request) Successful in 13m10s

(fix): harden concurrent lifecycle
(tests): add regression coverage
(doc): update v1.2 guidance
This commit is contained in:
2026-08-20 11:08:45 +03:00
parent 29b208eeec
commit 24040fe164
37 changed files with 1129 additions and 157 deletions
+37 -4
View File
@@ -18,6 +18,8 @@ import (
"github.com/alitto/pond/v2"
)
const observerShutdownTimeout = 5 * time.Second
func (bot *Bot[T]) addTokenReplacer(loggers ...*sneklog.Logger) {
if bot.token == "" {
return
@@ -30,6 +32,19 @@ func (bot *Bot[T]) addTokenReplacer(loggers ...*sneklog.Logger) {
}
}
func (bot *Bot[T]) closeReplacedLogger(old *sneklog.Logger, owned bool, replacements ...*sneklog.Logger) {
if old == nil || !owned || len(replacements) == 0 || replacements[0] == old {
return
}
if slices.Contains(replacements[1:], old) {
bot.detachedOwnedLoggers = appendUniqueLogger(bot.detachedOwnedLoggers, old)
return
}
if err := old.Close(); err != nil && bot.logger != nil && bot.logger != old {
bot.logger.Errorln(err)
}
}
func appendUniqueLogger(loggers []*sneklog.Logger, logger *sneklog.Logger) []*sneklog.Logger {
if logger == nil {
return loggers
@@ -80,26 +95,32 @@ func (bot *Bot[T]) initLoggers(opts *BotOpts) {
format, formatter := opts.LogFormat, opts.LogFormatter
if bot.logger == nil {
bot.logger = utils.CreateLogger("BOT", level, format, formatter)
bot.loggerOwned = true
if opts.WriteToFile {
path := fmt.Sprintf("%s/main.log", strings.TrimRight(opts.LoggerBasePath, "/"))
logger, err := utils.CreateFileLogger("BOT", level, path, format, formatter)
if err != nil {
bot.logger.Errorln(err)
} else {
_ = bot.logger.Close()
bot.logger = logger
bot.loggerOwned = true
}
}
}
if opts.UseRequestLogger && bot.requestLogger == nil {
bot.requestLogger = utils.CreateLogger("REQUESTS", level, format, formatter)
bot.requestLoggerOwned = true
if opts.WriteToFile {
path := fmt.Sprintf("%s/requests.log", strings.TrimRight(opts.LoggerBasePath, "/"))
logger, err := utils.CreateFileLogger("REQUESTS", level, path, format, formatter)
if err != nil {
bot.logger.Errorln(err)
} else {
_ = bot.requestLogger.Close()
bot.requestLogger = logger
bot.requestLoggerOwned = true
}
}
}
@@ -124,17 +145,29 @@ func (bot *Bot[T]) beginRun() error {
}
func (bot *Bot[T]) finishRun() {
bot.stopObserverDispatcher()
ctx, cancel := context.WithTimeout(context.Background(), observerShutdownTimeout)
if err := bot.stopObserverDispatcher(ctx); err != nil && bot.logger != nil {
bot.logger.Errorln(err)
}
cancel()
bot.runStateMu.Lock()
bot.running = false
bot.runStateMu.Unlock()
}
func (bot *Bot[T]) stopObserverDispatcher() {
func (bot *Bot[T]) stopObserverDispatcher(ctx context.Context) error {
if bot.observerAsync == nil {
return
return nil
}
bot.observerAsync.close()
return bot.observerAsync.close(ctx)
}
func (bot *Bot[T]) startAsyncTask(task func()) {
bot.middlewareWG.Add(1)
go func() {
defer bot.middlewareWG.Done()
task()
}()
}
func nextPollRetryDelay(prev time.Duration) time.Duration {