Bhargav
Bhargav

Reputation: 713

python asyncio REST api call gives error

I am trying to call a REST API async using asyncio but i keep getting the error "coroutine was never awaited" which i understand. But i want this behavior, i want my function to end just by posting and not waiting for the result. Here is my code

async def callCoroutine:
    #call a REST API 

def lambda_handler(event, context):   
    loop = asyncio.get_event_loop()
    task = loop.create_task(callCoroutine(data))
    return

Can someone help?

Upvotes: 2

Views: 1288

Answers (3)

Char
Char

Reputation: 818

In your case, the main thread is running synchronously. So you need to run the asyncio loop in another thread Using asyncio.run_coroutine_threadsafe.

import asyncio
import threading

# Run asyncio loop in other thread
loop = asyncio.new_event_loop()
threading.Thread(target=loop.run_forever).start()


async def call_coroutine(data):
    # call a REST API 
    return


def lambda_handler(event, context):   
    # Run the coroutine on the loop of other thread
    future = asyncio.run_coroutine_threadsafe(call_coroutine(data), loop)
    # If need to get result: 
    result = future.result()  # This will block the main thread

    do_something_else()
    return

# If need to stop the asyncio loop
loop.call_soon_threadsafe(loop.stop)

Upvotes: 1

wowkin2
wowkin2

Reputation: 6355

For the current example, you need to have running loop somewhere (e.g. if you have some web-server or worker - loop.run_forever())

Fixed code example with running loop

import asyncio


async def callCoroutine(data):
    print('This is data: %s' % data)


def lambda_handler(event, context):   
    loop = asyncio.get_event_loop()
    task = loop.create_task(callCoroutine(context))
    return

lambda_handler(None, {'a': 1})

loop = asyncio.get_event_loop()
loop.run_forever()

Example with run_in_executor()

import asyncio
import requests


def call_rest_api(data):
    print('Triggered REST API in background')
    response = requests.get(data['url'])
    print('Response: %s' % response)


async def main(loop):
    print('Some operations here...')

    data = {'url': 'http://example.com#some_rest_api'}
    loop.run_in_executor(None, call_rest_api, data)

    print('Continue work of main thread...')


if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main(loop))

Example with simple await (if you need to call API syncronously)

But it is not necessary to use asyncio if you want to write synchronous code.

import asyncio
import requests


def call_rest_api(data):
    print('Triggered REST API in background')
    response = requests.get(data['url'])
    print('Response: %s' % response)


async def main(loop):
    print('Some operations here...')

    data = {'url': 'http://example.com#some_rest_api'}
    await call_rest_api(data)

    print('Continue work of main thread...')


if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main(loop))

Can you provide more verbose example of what you have and what you want to achive?

Upvotes: 1

0az
0az

Reputation: 360

If you just need to call the API, disregarding the result, you can use an Executor in another thread, which will not block the main thread.

To run in an Executor, use AbstractEventLoop.run_in_executor() with an Executor from concurrent.futures.

Upvotes: 1

Related Questions