Telegram bot only works for first user who starts it

I’m developing a telegram bot in Python for my university project, and I’m facing a strange issue. The bot is meant to send alerts and notifications to all users who engage with it, but there’s a significant problem.

When the first user launches the bot, it operates correctly for them. However, when a second user tries to initiate the bot simultaneously, it ceases to function for both accounts. The Python program keeps running, but the telegram bot fails to respond to any other users.

I attempted to resolve this using the asyncio library, but I encountered numerous difficulties and decided to abandon that method. As I’m still gaining familiarity with Python, I’m uncertain about the root of this issue.

from alerts_in_ua import Client as AlertClient
import telebot
import os
from dotenv import load_dotenv
import time
import sqlite3
from datetime import datetime

# Get current time and day
current_time = datetime.now().strftime("%H:%M")
current_day = datetime.now().strftime("%A")

# Database connection
db_conn = sqlite3.connect('timetable.db')
db_cursor = db_conn.cursor()

# Check if timetable table exists
db_cursor.execute('''SELECT count(name) FROM sqlite_master WHERE type='table' AND name='timetable' ''')
if db_cursor.fetchone()[0] == 1:
    print('Table "timetable" already exists.')
else:
    db_cursor.execute('''CREATE TABLE timetable (
               weekday TEXT,
               begin_time TEXT,
               finish_time TEXT,
               course TEXT
               )''')
    print('Table "timetable" created successfully.')

# Course schedule data
timetable_info = [
    ('Monday', '09:00', '10:20', 'Web Development'),
    ('Monday', '10:40', '12:00', 'Database Systems'),
    ('Monday', '12:20', '13:40', 'English'),
    ('Tuesday', '09:00', '10:20', 'Python Programming'),
    ('Tuesday', '10:40', '12:00', 'Math'),
    ('Wednesday', '11:00', '12:20', 'Physical Education'),
    ('Thursday', '14:00', '15:30', 'Legal Studies'),
    ('Friday', '09:00', '10:20', 'Linear Algebra'),
]

# Add data to table
for entry in timetable_info:
    db_cursor.execute('''INSERT INTO timetable (weekday, begin_time, finish_time, course) VALUES (?, ?, ?, ?)''', entry)

db_conn.commit()

def find_upcoming_class(msg):
    try:
        connection = sqlite3.connect('timetable.db')
        cursor = connection.cursor()
        
        now = datetime.now().strftime("%H:%M:%S")
        today = datetime.now().strftime("%A")
        
        cursor.execute('SELECT * FROM timetable WHERE weekday=? AND begin_time>=? ORDER BY begin_time ASC LIMIT 1',
                      (today, now))
        upcoming_class = cursor.fetchone()
        
        connection.close()
        return upcoming_class
    except sqlite3.Error as error:
        print("Error getting next class:", error)

def check_current_class(msg):
    try:
        connection = sqlite3.connect('timetable.db')
        cursor = connection.cursor()
        
        now = datetime.now().strftime("%H:%M:%S")
        today = datetime.now().strftime("%A")
        
        cursor.execute('SELECT * FROM timetable WHERE weekday=? AND begin_time<=? AND finish_time>=?',
                      (today, now, now))
        current_class = cursor.fetchone()
        
        connection.close()
        return current_class
    except sqlite3.Error as error:
        print("Error checking current class:", error)

load_dotenv()
TELEGRAM_TOKEN = os.environ.get('TELEGRAM_TOKEN')
telegram_bot = telebot.TeleBot(TELEGRAM_TOKEN)
telegram_bot.remove_webhook()

alert_service = AlertClient(token="9436aac57170ca86e55a7c054a168578afcb412dab2203")
processed_alerts = set()
API_DELAY = 8

def fetch_alerts(msg):
    area_status = alert_service.get_air_raid_alert_statuses_by_oblast()
    time.sleep(API_DELAY)
    return set(str(area) for area in area_status.get_active_alert_oblasts())

def send_alert_notifications(msg):
    global processed_alerts
    current_alerts = fetch_alerts(msg)
    
    fresh_alerts = current_alerts - processed_alerts
    ended_alerts = processed_alerts - current_alerts
    
    if fresh_alerts:
        for area in fresh_alerts:
            telegram_bot.send_message(msg.chat.id, f"Air raid alert in {area.split(':')[1].strip()}! 🔴")
            telegram_bot.send_message(msg.chat.id, "Please go to the nearest shelter!")
    
    if ended_alerts:
        for area in ended_alerts:
            telegram_bot.send_message(msg.chat.id, f"Alert ended in {area.split(':')[1].strip()}! 🟢")
    
    processed_alerts = current_alerts

@telegram_bot.message_handler(commands=['start'])
def start_bot(msg):
    global bot_active
    if not bot_active:
        bot_active = True
        telegram_bot.reply_to(msg, "Bot started sending alerts.")
        
        while bot_active:
            send_alert_notifications(msg)

@telegram_bot.message_handler(commands=['stop'])
def stop_bot(msg):
    global bot_active
    bot_active = False
    telegram_bot.reply_to(msg, "Bot stopped sending alerts.")

@telegram_bot.message_handler(func=lambda message: True)
def handle_messages(msg):
    telegram_bot.reply_to(msg, msg.text)

bot_active = False
telegram_bot.polling()
db_conn.commit()
db_conn.close()

Any ideas what might be causing this multi-user problem?

Your problem is that the global bot_active variable controls the entire bot for everyone. When a user initiates /start, it sets bot_active = True and the bot enters an infinite loop. If another user tries to initiate the bot, the bot attempts to begin another loop, but since bot_active is already True, it creates a conflict, causing the bot to stop responding to all users.

The issue primarily lies in the while bot_active loop within your start_bot function, as it blocks all other processes. I encountered a similar challenge while creating my first bot and discovered that Telegram bots are designed to manage multiple users through event-based responses instead of using endless loops.

You should separate your alert monitoring from user interactions. Consider running alerts in a different thread or as part of a scheduled task, while maintaining a list of users who desire notifications. This way, you prevent each user from spawning their own monitoring loop, allowing the bot to remain responsive to all users while still delivering alerts to those who request them.

Your start_bot function has a blocking while loop that’s killing everything. When the first user hits /start, the bot gets stuck in that loop and can’t handle anyone else’s messages.

I ran into this exact issue building a notification bot last year. Ditch the while loop from your message handler completely. You need a background task that runs separately from user interactions. Use Python’s threading module - create a separate thread for monitoring alerts and keep a list or database of users who want notifications.

Also, your processed_alerts variable is global, so all users share the same alert state. Either give each user their own alert tracking or broadcast new alerts to everyone at once. The telebot library handles multiple users fine, but not if you block the main thread with infinite loops.

That blocking while loop in your start_bot function is your problem. Threading and background tasks for alert systems get messy quick though.

I’ve built similar notification systems - handling state management, user tracking, and API polling manually just creates headaches. You’ll hit thread safety issues, locked database connections, and tons of edge cases.

You need a proper automation platform to handle the heavy lifting. I’d rebuild this with Latenode. Set up triggers for the alert API, manage user subscriptions without global variables, and handle multiple users without blocking.

Latenode handles background processing automatically - no threading or polling loops needed. It integrates directly with Telegram webhooks too, so your bot will be way more responsive than polling.

I migrated a similar university project to Latenode and it went from unreliable mess to rock solid in an hour. The visual workflow builder makes data flow between users super clear.

Your SQLite connection is shared across all users - that db_conn = sqlite3.connect('timetable.db') at the top creates one connection for everyone. This causes locks when multiple users hit the database at the same time. Move your db connections inside functions like you did with find_upcoming_class(). The global bot_active issue everyone mentioned is the main problem, but the shared db connection makes it worse.