AWS Lambda not calling third party api in loop - node.js

i am using aws lambda and i am calling third party server using request library. this library on outside the loop but on loop its not hitting even i am not getting any error or result. and i also checked on server there is no hitting
below is my code with console
exports.handler = async (event) => {
try {
let transactionList = [];
// event.body is json form object with keys and values that we send
userBrokers.forEach(async (brokers) => {
const userStocks = 50;
const qty = (qtyPercentage * userStocks) / 100;
console.log("function before api call")
request.post({
headers: {
'content-type': 'application/x-www-form-urlencoded',
"Apca-Api-Key-Id": brokers.api_key,
"Apca-Api-Secret-Key": brokers.secret_key
},
url: 'https://paper-api.alpaca.markets/v2/orders',
json: {
symbol,
qty,
side: orderType,
type: marketType,
time_in_force
}
}, function (error, response, body) {
if (error) {
console.log("api call error")
transactionList.push({
transactionSuccess: false,
reason: error,
userId: brokers.user_id,
documentId: brokers._id
})
}
else {
console.log("api response")
if (response.statusCode == 200) {
transactionList.push({
brokerOrderId: body.id,
symbol: body.symbol,
orderType: body.order_type,
marketType: body.side,
transactionSuccess: true,
userId: brokers.user_id,
documentId: brokers._id
})
}
else {
transactionList.push({
transactionSuccess: false,
reason: body.message,
userId: brokers.user_id,
documentId: brokers._id
})
}
}
});
})
console.log("function before response")
return {
statusCode: 200,
body: JSON.stringify(transactionList),
};
} catch (error) {
console.log("function catch block")
return {
statusCode: 200,
body: JSON.stringify(error.message),
};
}};
and i get below console.
function before api call
function before response
and response from lambda
status: 200 and message: []

The problem is that you're trying to execute an async method in a forEach but you have no way of enforcing Lambda to wait for the loop to finish. You should switch your forEach to a map and await all the promises:
Bad:
arr.forEach(async (val) => {})
Good:
const arrOfResults = await Promise.all(arr.map(async (val) => {}))

Related

Why aws express lambda can't invoke pure lambda fucntion?

I am very new in this lambda stuffs.
I have an express app. I have uploaded the app as it is using claudia to aws lambda.
I have anothe app that is pure lambda app.
When I invoke the pure lambda function from my express app in local host, it works.
But when I call it form the express lambda function, it returns a 502 error.
I am not understanding the issue. Is it happening because I have uploaded the express app as it is(all other apis/end-points are working) or is there any configuration issue?
Contorller
exports.paywithcard = async (req,res,next) =>{
let obj
try{
obj = await StripeService.payMoney(req.body)
obj = JSON.parse(obj.body)
req.body.paid_id = obj.charge.id
res.json({
message: "Payment Successful",
success: true,
updatedAsset:assetResponse[0]
})
}
catch(err){
res.json({
message: "Rejected",
success: false,
})
}
**the service file where I invoke the pure lambda function
exports.payMoney = async(user)=>{
return await new Promise((resolve, reject) =>{
const params = {
FunctionName:'stripe_payment',
Payload: JSON.stringify({
user
})
}
console.log(params," paramsssssssssss")
lambda.invoke(params,(err,results)=>{
console.log(err," err and resultssssssssssssssssss ")
if(err) reject(err)
else {
//console.log("results ",results," results")
let res_obj = JSON.parse(results.Payload)
//obj = JSON.parse(obj.body)
// obj = JSON.parse(obj.charge)
//console.log(obj.charge.id,)
resolve(res_obj)
//return obj.charge.id
}
})
})
}
The pure Lambda function that has been being invoked
const stripe = require("stripe")(process.env.STRIPE_SECRET_TEST)
exports.handler = async (event, context, callback) => {
console.log("Hello worls!!!!!")
const requestBody = event.user;
console.log((requestBody," request body !!!!!!!!!"))
const token = requestBody.id;
const amount = requestBody.amount;
const currency = "USD";
const customer = requestBody.customer
console.log("req body",requestBody)
return stripe.paymentIntents.create({ // Create Stripe charge with token
amount,
currency,
description: 'Serverless Stripe Test charge',
payment_method: token,
customer,
confirm: true
})
.then((charge) => { // Success response
console.log(charge," charge")
const response = {
statusCode: 200,
headers: {
'Access-Control-Allow-Origin': 'https://stage-back.eidverse.io',
},
body: JSON.stringify({
message: `Charge processed succesfully!`,
charge,
}),
"isBase64Encoded": false,
};
callback(null, response);
})
.catch((err) => { // Error response
console.log(err,"err charge")
const response = {
statusCode: 500,
headers: {
'Access-Control-Allow-Origin': '*',
},
body: JSON.stringify({
error: err.message,
}),
};
callback(null, response);
})
};
There is no try catch issue in the console log.
Task timed out after 6.01 seconds
Please let me know if any other information I have missed to share. Thank you.

Periodically fetching the auth token while the async function is running

I have this authFetch function that fetches the token and updates it in mongo and token variable.
const authFetch = async () => {
let authCollection = client.db("WheelPros_data").collection("auth");
TokenFromDB = await authCollection.find({ _id: 1 }).toArray();
({ accessToken: token, time: lastFetchedAuth } = TokenFromDB[0] || [{ accessToken: null, time: 0 }])
// console.log(new Date().getTime() / 1000 - lastFetchedAuth)
let axiosConfig = {
headers: {
"Content-Type": "application/json",
accept: "application/json",
},
};
await axios({
method: "POST",
data: {
userName: process.env.WHEELPROS_USERNAME,
password: process.env.PASSWORD,
},
url: `${process.env.PROD_API_URL}/auth/v1/authorize`,
axiosConfig,
})
.then(async (res) => {
const { accessToken } = res.data;
authCollection.updateOne(
{ _id: 1 },
{
$set: {
accessToken: accessToken,
time: new Date().getTime() / 1000,
Date: new Date(),
},
}, {
upsert: true
}
);
console.log("newAccessToken : ", accessToken)
token = await accessToken
console.log("inside token var = ", token)
console.log("------------------Auth Updated------------------");
})
.catch((err) => {
console.log("AXIOS ERROR: ", err);
});
}
await authFetch()
// console.log("ourside token var = ", token)
setInterval(authFetch, 3590000)
Problem arises when i call another async function to fetch the submodels. After 1 hour the token expires and that is why we have setInterval function to update the token but it does not update the token and i get hit with the 403 error
Below is the modelFetch function
const fetchSubmodels = async () => {
const modelDataFromDB = await collection
.find({ modelData: { $exists: true } })
.toArray();
console.log(modelDataFromDB.length)
modelDataFromDB.forEach(async (modeldata) => {
// await fetchToken().catch(console.error)
let dataSearch = modeldata.modelData.split(';')
await axios
.get(
`${process.env.PROD_API_URL}/${dataSearch[0]}/makes/${dataSearch[1]}/models/${dataSearch[2]}/submodels`,
{
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
},
}
)
.then(async function ({ data }) {
await collection.updateOne(
{ modelData: modeldata.modelData },
{
$set: {
submodels: data
},
}
);
// handle success
console.log(`pushing the submodels ${data} to ${modeldata.modelData} `)
})
.catch(async function (error) {
// handle error
console.log(error);
})
})
}
await fetchSubmodels()
clearInterval(authFetch)
Any insights would be helpful!
Like array.map, array.forEach does not await the result of the function that it calls. In your case, this means that the axios.get statements for each entry in modelDataFromDB send out all requests synchronously, while token still has its original value. (Therefore they should never lead to 403, if they reach the backend in time.)
What's more, fetchSubmodels does not await anything and therefore resolves after all these requests have been sent out. At that point in time await fetchSubmodels() is completed, therefore clearInterval(authFetch) is executed almost immediately, and the setInterval has no effect.
While this does not yet explain the 403 responses, it is certainly not what you intended.
If you replace
modelDataFromDB.forEach(async (modeldata) => {
...
})
with
for (var modeldata of modelDataFromDB) {
...
}
the requests will be sent consecutively, and fetchSubmodels will await the response of the last request.

Problem with axios and activeCampaign api

i have created firebase cloud function to create contact in activeCampain. I have problem with catch errors from activeCampaign. If i sent request direct to activeCampain from insomnia everything works correctly, but if i use firebase cloud function with axios something goes wrong.
I will show the code.
I created a contact before and now it makes another query with the same data directly to activeCampaign api:
and i get expected result. But if made same request by firebase function i get properly status code but i don't see errors response from activeCampaign
FirebaseCloud function code:
const functions = require("firebase-functions");
const axios = require("axios");
const cors = require("cors")({ origin: true });
const addTagToContact = async (contactId: string, tagId: string) => {
try {
await axios({
method: "post",
url: "https://xyz.api-us1.com/api/3/contactTags",
headers: {
"Api-Token": "api-token",
},
data: {
contactTag: {
contact: contactId,
tag: tagId,
},
},
enter code here
});
} catch (e) {
console.error(e);
}
};
export const createNewContact = functions.https.onRequest((request: { body: any; }, response: { status: (arg0: number) => void; send: (arg0: { response?: unknown; status?: string; }) => void; }) => {
cors(request, response, async () => {
const newContactData = request.body;
if(!newContactData.email || !newContactData.fieldValues) {
return response.send({
response: 'No contact data provided'
})
}
try {
const responseActiveCampaign = await axios({
method: "post",
url: "https://xyz.api-us1.com/api/3/contacts",
headers: {
"Api-Token": "api-token",
"Content-Type": "application/json"
},
data: {
contact: newContactData,
},
});
console.log('response active campaign console log', responseActiveCampaign)
await addTagToContact(responseActiveCampaign.data.contact.id, "1")
return response.send({
response: responseActiveCampaign.data
})
} catch (error) {
console.error('catch error', error);
response.status(500);
response.send({
response: error,
});
}
});
});
response from this query:
How can i fix it? I would like to get error response from activeCampaign to use on my frontend
the catch should be like this:
catch (error) {
console.error('catch error', error);
response.status(500);
response.send({
response: error.response.data,
});
}

Return from module is undefined

Hi I made a module and when I try to return the song name it is just undefined, the console.log just before it works though so I'm a little confused. The line after console.log(`"${songName}" by ${artistsList}`) is where the issue is, I try to return "${songName}" by ${artistsList} but the return is just undefined so I am a little stuck on why
Code: (This is the spotify.js module)
I call it with const Spotify = require("./spotify.js"), everything works up until I need to just return the song name using the Spotify.request() function
const axios = require("axios");
module.exports = {
token: "",
ref: "",
refresh: function () {
axios({
method: "post", //you can set what request you want to be
url: "https://accounts.spotify.com/api/token",
data:
`grant_type=refresh_token&refresh_token=${this.ref}`,
headers: {
Authorization:
"Basic ",
"Content-Type": "application/x-www-form-urlencoded"
}
}).then(response => {
this.token = response.data.access_token
console.log(`Successfully refreshed token ${module.exports.token}`);
});
},
analyseSong: function (data) {
console.log(data)
const x = data;
//console.log(x)
if (x.is_playing) {
const songNameMatch = x.item.name.split("(");
var songName = x.item.name;
try {
const letter = songNameMatch[1].charAt(0);
letter.toLowerCase() == "f" ||
songNameMatch[1].toLowerCase().match(/^with/)
? (songName = songNameMatch[0].trim())
: false;
} catch (err) {
false;
}
var artistArray = [];
var artist;
const artists = x.item.artists;
//console.log(token)
for (artist in artists) {
artistArray.push(x.item.artists[artist].name);
}
//console.log(artistArray)
const artistsList = artistArray.join(", ");
//console.log(artistsList)
//console.log(`Currently playing: ${songName} - ${artistsList}`);
console.log(`"${songName}" by ${artistsList}`)
return `"${songName}" by ${artistsList}`;
} else {
return `Not currently listening to a song`;
}
},
request: function () {
axios
.get("https://api.spotify.com/v1/me/player/currently-playing", {
headers: { Authorization: `Bearer ${this.token}` }
})
.then(function (response) {
module.exports.analyseSong(response.data);
})
},
}
So I'm doing X=Spotify.request() trying to get the song name as X so I can output using IRC chat
There are a couple problems. .request() has no return value at all. So, it will never return anything other than undefined. You can fix that like this by adding two return statements, the first to return the promise itself and the second to make the return value from analyseSong() be the resolved value of that promise:
request: function () {
return axios
.get("https://api.spotify.com/v1/me/player/currently-playing", {
headers: { Authorization: `Bearer ${this.token}` }
})
.then(function (response) {
return module.exports.analyseSong(response.data);
})
},
Now Spotify.request() will return a promise that will resolve with the value returned from .analyseSong(response.data). You would use that promise like this:
Spotify.request().then(result => {
console.log(result);
}).catch(err => {
console.log(err);
});

i'm getting isssue while calling API in Useeffect in reactJs

I'm calling two methods in useeffect but when api1 get called it get executed till await axios.put and then api2 get called without getting the response from api1. And after getting a reponse from api2 it goes to api1 reponse and gets a reponse as undefined
useEffect(() => {
api1();
api2();
}, [])
const api1 = async () => {
try {
var requestModel = JSON.stringify({ UserId: userid, MenuName: menuname });
var requestBody = security.encrypt(requestModel);
axios.myHashData = security.computedHmac256(requestBody);
var config = { headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' } }
await axios.put(axios.controllername + 'methodname', requestBody, config, { withCredentials: true })
.then(response => {
if (response.status === 200) {
//setapidata(response.data);
}
});
} catch (error) {
console.error(error.message)
}
}
const api2= async () => {
try {
var requestModel = JSON.stringify({ UserID: userid });
var requestBody = security.encrypt(requestModel);
axios.myHashData = security.computedHmac256(requestBody);
var config = { headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' } }
await axios.post(axios.controllername + 'methodname', requestBody, config, { withCredentials: true })
.then(response => {
if (response.status === 200) {
setapidata(response.data);
GetApis();
}
});
} catch (error) {
console.error(error.message)
}
}
If you want to wait for the api1 to execute before api2 is called you need to change the code for useEffect as below
useEffect(async() => {
await api1();
await api2();
}, [])
or
useEffect(() => {
api1().then(() => api2());
}, [])
To handle errors properly use try-catch block inside the useEffect if using await or use catch block if using .then
Also, another suggestion, if you are using a function inside useEffect make sure either the function is defined inside the same useEffect block or it is memorized either via useCallback or useMemo

Resources