I want to create a web application that works alongside a Telegram bot so I can trigger bot functions from my web interface. I’m having trouble getting both services to work at the same time.
import streamlit as st
from telegram import Update
from telegram.ext import Updater, CallbackContext, MessageHandler, Filters
def reply_message(update: Update, context: CallbackContext) -> None:
update.effective_chat.send_message(text="Hello there")
def start_web_app():
st.set_page_config(page_title="Bot Control Panel", page_icon=":robot_face:", layout="wide")
def initialize_telegram_bot() -> None:
bot_updater = Updater('YOUR_BOT_TOKEN_HERE')
bot_dispatcher = bot_updater.dispatcher
message_handler = MessageHandler(Filters.all, reply_message)
bot_dispatcher.add_handler(message_handler)
bot_updater.start_polling()
bot_updater.idle()
if __name__ == '__main__':
start_web_app()
initialize_telegram_bot()
When I launch this with streamlit run app.py, I get this threading error:
ValueError: signal only works in main thread of the main interpreter
I tried removing the idle() call but then I get a conflict error saying another bot instance is already running. Adding caching decorators didn’t help either. How can I make these two components work together properly?
Streamlit runs its own event loop and hates blocking operations like updater.idle(). I hit this exact problem building a dashboard with a Telegram bot. Here’s what fixed it for me: run the bot in a separate thread without idle, and use start_polling() with block=False. You’ll have to manage the bot lifecycle yourself though. python import threading import streamlit as st from telegram.ext import Updater def run_bot(): updater = Updater('YOUR_TOKEN') # Add your handlers here updater.start_polling(drop_pending_updates=True) # Don't call idle() here if 'bot_started' not in st.session_state: bot_thread = threading.Thread(target=run_bot, daemon=True) bot_thread.start() st.session_state.bot_started = True The daemon thread kills the bot when Streamlit shuts down. If you’re deploying to production, consider webhooks instead of polling - they’re way more reliable for concurrent stuff.
Fought with this exact setup for months before finding a better way. The problem is Streamlit wants full control of the main thread - any blocking calls create conflicts. Don’t bother with threading or async headaches. I use Redis as a message queue between the web interface and bot. Run the Telegram bot as a separate process (not a thread) and have it talk to Streamlit through Redis channels. Both services stay isolated and you dodge all the signal handling mess. Your web interface pushes commands to Redis queues, the bot process grabs them independently. Way more stable than shoving everything into one process, especially when you need to scale or deploy to cloud platforms that hate complex threading.
asyncio is your friend here! Streamlit + Telegram bots work great with async/await. Use python-telegram-bot’s async version instead of the old sync one. Wrap everything in asyncio tasks and skip the threading headache completely. Way cleaner than daemon threads.