fix(telegram): reconnect polling and fail fast on initial connect
This commit is contained in:
parent
214b201bfa
commit
619192bb4d
1 changed files with 90 additions and 23 deletions
|
|
@ -29,6 +29,7 @@ type TelegramChannel struct {
|
||||||
transcriber *voice.GroqTranscriber
|
transcriber *voice.GroqTranscriber
|
||||||
placeholders sync.Map // chatID -> messageID
|
placeholders sync.Map // chatID -> messageID
|
||||||
stopThinking sync.Map // chatID -> thinkingCancel
|
stopThinking sync.Map // chatID -> thinkingCancel
|
||||||
|
privacyOnce sync.Once
|
||||||
}
|
}
|
||||||
|
|
||||||
type thinkingCancel struct {
|
type thinkingCancel struct {
|
||||||
|
|
@ -81,34 +82,13 @@ func (c *TelegramChannel) SetTranscriber(transcriber *voice.GroqTranscriber) {
|
||||||
func (c *TelegramChannel) Start(ctx context.Context) error {
|
func (c *TelegramChannel) Start(ctx context.Context) error {
|
||||||
logger.InfoC("telegram", "Starting Telegram bot (polling mode)...")
|
logger.InfoC("telegram", "Starting Telegram bot (polling mode)...")
|
||||||
|
|
||||||
updates, err := c.bot.UpdatesViaLongPolling(ctx, &telego.GetUpdatesParams{
|
updates, err := c.startLongPolling(ctx)
|
||||||
Timeout: 30,
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to start long polling: %w", err)
|
return fmt.Errorf("failed to start long polling: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
c.setRunning(true)
|
c.setRunning(true)
|
||||||
logger.InfoCF("telegram", "Telegram bot connected", map[string]interface{}{
|
go c.runPollingLoop(ctx, updates)
|
||||||
"username": c.bot.Username(),
|
|
||||||
})
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
return
|
|
||||||
case update, ok := <-updates:
|
|
||||||
if !ok {
|
|
||||||
logger.InfoC("telegram", "Updates channel closed, reconnecting...")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if update.Message != nil {
|
|
||||||
c.handleMessage(ctx, update)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -119,6 +99,93 @@ func (c *TelegramChannel) Stop(ctx context.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *TelegramChannel) runPollingLoop(ctx context.Context, updates <-chan telego.Update) {
|
||||||
|
defer c.setRunning(false)
|
||||||
|
|
||||||
|
backoff := time.Second
|
||||||
|
const maxBackoff = 30 * time.Second
|
||||||
|
|
||||||
|
for {
|
||||||
|
restart := false
|
||||||
|
for !restart {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return
|
||||||
|
case update, ok := <-updates:
|
||||||
|
if !ok {
|
||||||
|
logger.WarnC("telegram", "Updates channel closed, restarting long polling")
|
||||||
|
restart = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if update.Message != nil {
|
||||||
|
c.handleMessage(ctx, update)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
nextUpdates, err := c.startLongPolling(ctx)
|
||||||
|
if err != nil {
|
||||||
|
logger.ErrorCF("telegram", "Failed to restart long polling", map[string]interface{}{
|
||||||
|
"error": err.Error(),
|
||||||
|
"retry_after": backoff.String(),
|
||||||
|
})
|
||||||
|
timer := time.NewTimer(backoff)
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
timer.Stop()
|
||||||
|
return
|
||||||
|
case <-timer.C:
|
||||||
|
}
|
||||||
|
if backoff < maxBackoff {
|
||||||
|
backoff *= 2
|
||||||
|
if backoff > maxBackoff {
|
||||||
|
backoff = maxBackoff
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
backoff = time.Second
|
||||||
|
updates = nextUpdates
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *TelegramChannel) startLongPolling(ctx context.Context) (<-chan telego.Update, error) {
|
||||||
|
updates, err := c.bot.UpdatesViaLongPolling(ctx, &telego.GetUpdatesParams{
|
||||||
|
Timeout: 30,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.InfoCF("telegram", "Telegram bot connected", map[string]interface{}{
|
||||||
|
"username": c.bot.Username(),
|
||||||
|
})
|
||||||
|
c.privacyOnce.Do(func() {
|
||||||
|
botUser, meErr := c.bot.GetMe(ctx)
|
||||||
|
if meErr != nil {
|
||||||
|
logger.WarnCF("telegram", "Failed to fetch bot profile for privacy mode check", map[string]interface{}{
|
||||||
|
"error": meErr.Error(),
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !botUser.CanReadAllGroupMessages {
|
||||||
|
logger.WarnC("telegram", "Privacy mode is enabled: in group chats, bot only receives commands, replies, and @mentions")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return updates, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *TelegramChannel) Send(ctx context.Context, msg bus.OutboundMessage) error {
|
func (c *TelegramChannel) Send(ctx context.Context, msg bus.OutboundMessage) error {
|
||||||
if !c.IsRunning() {
|
if !c.IsRunning() {
|
||||||
return fmt.Errorf("telegram bot not running")
|
return fmt.Errorf("telegram bot not running")
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue