skip to Main Content

I have this function which works fine locally on my machine with python 3.8, but it throws runtime error on Google Cloud Functions.

def telegram_test(request):
    request_json = request.get_json()
    import datetime
    import pandas as pd
    from pyrogram import Client
    
    session_string = "...............38Q8uTHG5gHwyWD8nW6h................."
    # the rest of the authantication
    api_id = 32494131641215
    api_hash = "ioadsfsjnjksfgnfriuthg#qw]/zwq  ]w/lc ec,"

    # one of bbc channels on telegram you want to access
    channel_name = 'pyrogram'

    # if you only want to get messages older than 7 days in unix style
    seven_days = int((datetime.datetime.now() - datetime.timedelta(days=7)).timestamp())
    # call telegram with parameters such as limit and date
    # save the result to dataframe

    with Client(session_string,api_id,api_hash, takeout=True,workers=2) as app:
        hist_iter = app.iter_history(channel_name,offset_date=seven_days, limit=100)    
        msglist = [msg.__dict__ for msg in hist_iter]
        df = pd.DataFrame(msglist)
        print(df.head(5))
 
    return f'it works!:{request_json}'

The error message I get from GCF log:

File "/opt/python3.8/lib/python3.8/asyncio/events.py", line 639, in
get_event_loop raise RuntimeError(‘There is no current event loop in
thread %r.’ RuntimeError: There is no current event loop in thread
‘ThreadPoolExecutor-0_0’.

Update

I updated the code, the runtime error gone. but I am getting time out error.
I put the timeout 180 secondes, but still when I test the function times out on 60 seconds.

Here is the updated code. Is there something I am doing wrong?

async def foo():
    from datetime import datetime, timedelta
    from pandas import DataFrame
    from pyrogram import Client
    import asyncio

    session_string = "********zNmkubA4ibjsdjhsdfjlhweruifnjkldfioY5DE*********"    
    api_id = 325511548224831351
    api_hash = "jdffjgtrkjhfklmrtgjtrm;sesews;;wex"        
    channel_name = 'cnn'

    with Client(session_string, api_id, api_hash, takeout=True) as app:
        hist_iter = app.iter_history(
            channel_name, limit=10)
        msglist = [msg.__dict__ for msg in hist_iter]
        df = DataFrame(msglist)    
    return df
 
async def bar():
    return await foo() 

def test(request):
    from asyncio import run
    return run(bar())

2

Answers


  1. Chosen as BEST ANSWER

    The solution in the end was to change from Pyrogram to telethon and create the asyncio manaually before creating the client.

    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    

    Note: you need valid session string, otherwise when you test the function, it will wait for you to auth with mobile number. so first run this code locally and authenticate, then copy the session string to the cloud function.

    Here is the full code:

    from telethon.sessions import StringSession
    from telethon import TelegramClient
    from pandas import DataFrame
    import datetime
    import asyncio
    
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    
    api_id = 101010101
    api_hash = "jhafcgahagfbahgdbw17171736456gerf"
    session_string = "hjksdhjbdsfhgbdsabeyitrgdsbfsdbdiyfhsbddasbdjdksf="
    channel_name = 'bbcuzbek'
    seven_days = int((datetime.datetime.now() -
                      datetime.timedelta(days=7)).timestamp())
    
    
    
    
    client = TelegramClient(StringSession(session_string),
                            api_id, api_hash, loop=loop)
    
    time_format = "%d/%m/%Y, %H:%M:%S"
    download_date = datetime.datetime.now(
        tz=datetime.timezone.utc).strftime(time_format)
    
    cols = ["id", "date", "text", "views", "download_date"]
    
    
    async def foo():
        all_msgs = [[message.id, message.date.strftime(time_format), message.text, message.views, download_date] async for message in client.iter_messages(entity=channel_name, offset_date=seven_days, limit=10)]
        df = DataFrame(data=all_msgs, columns=cols)
        # write it to BQ
        # print(df)
        # async for message in client.iter_messages(entity=channel_name, offset_date=seven_days, limit=10):
        #     print(message.id, message.date, message.text, message.views)
        print("it runs")
    
        print(len(df))
        return None
    
    
    def test(request):
        with client:
            return client.loop.run_until_complete(foo())
    
    

    1. bar() is redundant
    2. You’re trying to return a dataframe. Is it a valid HTTP response?
    3. with -> async with
    4. hist_iter = app.iter_history() -> hist_iter = await app.iter_history()
    5. M.b. it waits for input?
      enter image description here
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search