Why can't I await calls to LambdaHelper.callAsync? - aws-lambda

I'm developing a vue.js application with node.js in the backend. The backend is also hosted by a lambda server on AWS.
On the backend, I'm trying to do the following:
let success = false;
let lh = new LambdaHelper();
success = await lh.callAsync('MyController', 'myMethod', params);
This calls MyController.myMethod(params). But it doesn't await.
If I put a console log immediately after the call to lh.callAsync(...) and print out the value of success, it prints out undefined. And if I put some console logs in myMethod, it prints them out after it prints out the value of success. This means it is not awaiting the call to lh.callAsync(...).
Now if I replace the last line with...
success = await require('MyController').myMethod(params)
...it works just fine (i.e. it awaits myMethod(...) and prints the value of success (true or false) after printing the console logs in myMethod(...)).
Is there a special trick to awaiting calls to methods through LambdaHelper.callAsync(...)? Thanks.

Related

Micropython: asyncio Server: get Client IP address

I am new in micropython and testing it out, if it can fit the needs for my next project. I have set up a script to test it and there I run three async jobs in an endless loop. one of them is a tiny webserver, which should act as an API. The construct is working fine, I just need to know, how can I get the clients IP address, which is calling my API webservice (it will be only a local IP, so no worries about reverse proxies etc.)? So I would like to have the clients IP in the Method APIHandling, in this snippet just to print it out:
async def APIHandling(reader, writer):
request_line = await reader.readline()
# We are not interested in HTTP request headers, skip them
while await reader.readline() != b"\r\n":
pass
request = str(request_line)
try:
request = request.split()[1]
except IndexError:
pass
print("API request: " + request + " from IP: ")
req = request.split('/')
#do some things here
response = html % stateis
writer.write(response)
await writer.drain()
await writer.wait_closed()
async def BusReader():
#doing something here
await asyncio.sleep(0)
async def UiHandling():
#doing something else here
await asyncio.sleep(0.5)
async def Main():
set_global_exception()
loop = asyncio.get_event_loop()
loop.create_task(asyncio.start_server(APIHandling, Networking.GetIPAddress(), 80))
loop.create_task(UiHandling())
loop.create_task(BusReader())
loop.run_forever()
try:
asyncio.run(Main())
finally:
asyncio.new_event_loop()
The only thing I found was this: Stream.get_extra_info(v) - but I do not have a Stream avaliable anywhere?
Note: This is just a snippet with the essential parts of my actual script, so you will find references to other classes etc. which are not present in this code example.
Nevermind, I was too stupid to see that "writer" is actually a Stream, where I can get the clients IP with writer.get_extra_info('peername')[0]

Asyncio: Fastapi with aio-pika, consumer ignores Await

I am trying to hook my websocket endpoint with rabbitmq (aio-pika). Goal is to have listener in that endpoint and on any new message from queue pass the message to browser client over websockets.
I tested the consumer with asyncio in a script with asyncio loop. Works as I followed and used aio-pika documentation. (source: https://aio-pika.readthedocs.io/en/latest/rabbitmq-tutorial/2-work-queues.html, worker.py)
However, when I use it in fastapi in websockets endpoint, I cant make it work. Somehow the listener:
await queue.consume(on_message)
is completely ignored.
This is my attempt (I put it all in one function, so its more readable):
#app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
print("Entering websockets")
await manager.connect(websocket)
print("got connection")
# params
queue_name = "task_events"
routing_key = "user_id.task"
con = "amqp://rabbitmq:rabbitmq#rabbit:5672/"
connection = await connect(con)
channel = await connection.channel()
await channel.set_qos(prefetch_count=1)
exchange = await channel.declare_exchange(
"topic_logs",
ExchangeType.TOPIC,
)
# Declaring queue
queue = await channel.declare_queue(queue_name)
# Binding the queue to the exchange
await queue.bind(exchange, routing_key)
async def on_message(message: IncomingMessage):
async with message.process():
# here will be the message passed over websockets to browser client
print("sent", message.body)
try:
######### Not working as expected ###########
# await does not await and websockets finishes, as there is no loop
await queue.consume(on_message)
#############################################
################ This Alternative code atleast receives some messages #############
# If I use this part, I atleast get some messages, when I trigger a backend task that publishes new messages to the queue.
# It seems like the messages are somehow stuck and new task releases all stucked messages, but does not release new one.
while True:
await queue.consume(on_message)
await asyncio.sleep(1)
################## one part #############
except WebSocketDisconnect:
manager.disconnect(websocket)
I am quite new to async in python. I am not sure where is the problem and I cannot somehow implement async consuming loop while getting inspired with worker.py from aio-pika.
You could use an async iterator, which is the second canonical way to consume messages from a queue.
In your case, this means:
async with queue.iterator() as iter:
async for message in iter:
async with message.process():
# do something with message
It will block as long as no message is received and will be suspended again after processing a message.
The solution was simply.
aio-pika queue.consume even though we use await is nonblocking, so
this way we consume
consumer_tag = await queue.consume(on_message, no_ack=True)
and at the end of connection we cancel
await queue.cancel(consumer_tag)
The core of the solution for me, was to make something asyncio blocking, so I used
this part of the code after consume
while True:
data = await websocket.receive_text()
x = await manager.send_message(data, websocket)
I dont use this code, but its useful as this part of the code waits for frontend websocket response. If this part of the code is missing, then what happens is that client connects just to get disconnected (the websocket endpoit is succefully executed), as there is nothing blocking

bot.get_all_channels() gets ignored discord.py

When obtaining all channels to send a message to all, the bot ignores the command. Here's my code.
async def lockdown(ctx):
allchannels = bot.get_all_channels()
overwrite = channel.overwrites_for(ctx.guild.default_role)
locked = overwrite.send_messages = False
await locked.send(allchannels, 'This server has been locked down.')
Try printing allchannel, you'll see where you did an error.
You can't use bot.get_all_channels() in this way that's all

Code is not delievered by SendCodeRequest without error and this happens only on server-side with Heroku

Here is my situation: the same Telethon code is used on my local machine and on the server. Requesting authorization code from local machine works fine. Requesting the code from the server does not produce any error, and code is not sent. Sometimes it works even from the server without any changes in code.
I suppose there might be some ip blocks or something related to the ip, cause that is the only thing which might differ on the server side: Heroku assign ip addresses dynamically, so, there might by some subnets which are blocked by Telegram API for some reason. But there is no error and that is really strange. There are too many ip addresses to disprove the hypothesis. I need to catch at least one ip address which gives me opposite results: one time code it recieved and another time does not. So I am stuck with this situation and have no ideas how it could be fixed or clarified.
global t
t = None
async def ssssendCode(phone):
global t
try:
if os.path.isfile(phone+'.session'):
logger.debug('client file exists')
else:
logger.debug('client file does not exist')
if t is None:
t = TelegramClient(phone, settings['telegramClientAPIId'], settings['telegramClientAPIHash'])
t.phone = phone
#t.phone_code_hash = None
await t.connect()
#response = await t.send_code_request(phone=phone,force_sms=True)
s3_session.resource('s3').Bucket('telethon').upload_file(str(phone)+".session", str(phone)+".session")
logger.debug(str(requests.get('https://httpbin.org/ip').text))
response = await t.send_code_request(phone=phone)
logger.debug(str(t.is_connected()))
except Exception as e:
response = str(e)
return str(response)
example of response to the local machine request
SentCode(type=SentCodeTypeSms(length=5), phone_code_hash='b5b069a2a4122040f1', next_type=CodeTypeCall(), timeout=120)
example of reponse to the server-side request
SentCode(type=SentCodeTypeSms(length=5), phone_code_hash='0e89db0324c1af0149', next_type=CodeTypeCall(), timeout=120)
send_code_request is the from the Telethon without modifications
async def send_code_request(
self: 'TelegramClient',
phone: str,
*,
force_sms: bool = False) -> 'types.auth.SentCode':
"""
Sends the Telegram code needed to login to the given phone number.
Arguments
phone (`str` | `int`):
The phone to which the code will be sent.
force_sms (`bool`, optional):
Whether to force sending as SMS.
Returns
An instance of :tl:`SentCode`.
Example
.. code-block:: python
phone = '+34 123 123 123'
sent = await client.send_code_request(phone)
print(sent)
"""
result = None
phone = utils.parse_phone(phone) or self._phone
phone_hash = self._phone_code_hash.get(phone)
if not phone_hash:
try:
result = await self(functions.auth.SendCodeRequest(
phone, self.api_id, self.api_hash, types.CodeSettings()))
except errors.AuthRestartError:
return await self.send_code_request(phone, force_sms=force_sms)
# If we already sent a SMS, do not resend the code (hash may be empty)
if isinstance(result.type, types.auth.SentCodeTypeSms):
force_sms = False
# phone_code_hash may be empty, if it is, do not save it (#1283)
if result.phone_code_hash:
self._phone_code_hash[phone] = phone_hash = result.phone_code_hash
else:
force_sms = True
self._phone = phone
if force_sms:
result = await self(
functions.auth.ResendCodeRequest(phone, phone_hash))
self._phone_code_hash[phone] = result.phone_code_hash
return result
Just in case: I have much more than 2 minutes between attempts to get a code from the local machine and server, so it is absolutely not the timeout issue. And moreover: even when requesting the code from the local right after half a minute from the failed server-side attemp: code is coming almost immediately.

Tornado cancel httpclient.AsyncHTTPClient fetch() from on_chunk()

Inside one of the handlers I am doing the following:
async def get(self):
client = httpclient.AsyncHTTPClient()
url = 'some url here'
request = httpclient.HTTPRequest(url=url, streaming_callback=self.on_chunk, request_timeout=120)
result = await client.fetch(request)
self.write("done")
#gen.coroutine
def on_chunk(self, chunk):
self.write(chunk)
yield self.flush()
The requests can sometimes be quite large and the client may leave while the request is still in progress of being fetched and pumped to the client. If this happens an exception will appear in the on_chunk function when self.write() is attempted. My question is how do I abort the remaining download if my client went away ?
If your streaming_callback raises an exception, the client request should be aborted. This will spam the logs with stack traces, but there's not currently a cleaner way to do it. You can override on_connection_close to detect when the client has disconnected and set an attribute on self that you can check in on_chunk.

Resources