pythontelethonquart

Telethon "Cannot send requests while disconnected" while getting channels in quart route


I'm using telethon and quart on the same loop. I need to listen for new messages and in the same time i would like to read all channels when a page is loaded.

But doing this will end in a ConnectionError: Cannot send requests while disconnected and i don't know how to handle this. Adding async with client: before the loop will cause sqlite3.OperationalError: database is locked. There's a chance to archieve what i want?

Here the relevant code:

...

executor = ProcessPoolExecutor(1)

...

# Telethon client
client = TelegramClient('bot', int(api_id), api_hash)

# Quart app
app = Quart(__name__, template_folder=None, static_folder=None, static_url_path=None)
main = Blueprint('main', __name__, template_folder='templates', static_folder='static', static_url_path='static')

...

@app.before_serving
async def startup():
    client.loop.run_in_executor(executor, telethon_start)


...

@client.on(events.NewMessage(incoming=True))
async def new_chat(event):
    #Do something with messages

...


@main.route('/new', methods=['GET', 'POST'])
async def new():

    channels = []
    async for dialog in client.iter_dialogs(): # Here the problem
        channels.append((dialog.id, dialog.name))

    return await render_template(
        'new_channel.html',
        channels=channels
    )


def telethon_start():
    with client:
        client.run_until_disconnected()


async def start(conf):
    app.register_blueprint(main, url_prefix=base_url)
    await hypercorn.asyncio.serve(app, conf)


if __name__ == '__main__':
    config = hypercorn.Config()
    config.bind = "127.0.0.1:" + str(expose_port)

    client.loop.run_until_complete(start(config))

Please help me!


Solution

  • The executor usage seems suspicious. You shouldn't really be needing that.

    Assuming @app.before_serving is called every time a request occurs, you will also be connecting the same client many times per request. This is wrong because each client instance should ideally only be connected once (you cannot reuse the same session multiple times).

    My recommendation is that you simply connect the client before serving your application like so:

    # @app.before_serving, startup and telethon_start removed entirely
    
    async def start(conf):
        async with client:
            # ^~~~~~~~~~~ starting the client now occurs here
            app.register_blueprint(main, url_prefix=base_url)
            await hypercorn.asyncio.serve(app, conf)