Cloud task doesn't run on time - google-cloud-platform

What I am trying to do is to change the data in firestore using cloud function and cloud task on a scheduled time. But cloud task doesn't run on time. It is executed right after adding task.
My code is like this.
index.js
exports.addTasks = functions.https.onCall((data, context) => {
const client = new tasks.CloudTasksClient()
const projectId = ...
const queue = ...
const location = ...
const parent = client.queuePath(projectId, location, queue)
const url = ... .cloudfunctions.net/doSomething?docId=' + docId
const task = {
httpRequest: {
httpMethod: 'POST',
url: url,
scheduleTime: {
seconds: 3 * 60 + Date.now() / 1000,
},
}
}
const request = {
parent: parent,
task: task,
}
client.createTask(request)
})
exports.doSomething = functions.https.onRequest((req, res) => {
var db = admin.firestore()
var docId = req.query.docId
var docRef = db.collection('people').doc(docId)
docRef.update({
changeHere: true,
})
})
I want to run doSomething function 3 minutes after addTasks is executed. What am I wrong with this?

scheduleTime is a property of the task object and not a property of httpRequest.
const task = {
httpRequest: {
httpMethod: 'POST',
url: url,
},
scheduleTime: {
seconds: 3 * 60 + Date.now() / 1000,
},
}
Here is the reference doc and sample code showing this.

Related

Items doesn't save correctly in dynamo db through the lambda function

In my react native application which has an AWS amplify backend I use a post confirmation lambda function to save the cognito users in my dynamo db data store. My post confirmation lambda function runs fine and I can see the newly created user in my dynamo db but I can't query that user inside my app and also I cannot see the user in admin UI interface. But after about several hours I can query that user and also see the user through admin UI. How to fix this ?
/**
* #type {import('#types/aws-lambda').APIGatewayProxyHandler}
*/
const aws = require("aws-sdk");
const ddb = new aws.DynamoDB();
const tableName = process.env.USERTABLE;
exports.handler = async (event) => {
// insert code to be executed by your lambda trigger
if(!event?.request?.userAttributes?.sub){
console.log("no sub provided")
return;
}
const now = new Date();
const timestamp = now.getTime();
const userItem = {
__typename: { S: 'User' },
_lastChangedAt: { N: timestamp.toString() },
_version: { N: "1" },
updatedAt: { S: now.toISOString() },
createdAt: { S: now.toISOString() },
id: { S: event.request.userAttributes.sub },
Name: { S: event.request.userAttributes.name },
Email: { S: event.request.userAttributes.email },
Phonenumb: { S: event.request.userAttributes.phone_number },
DeliveryAddress: { S: ''}
}
const params = {
Item: userItem,
TableName: tableName
}
try {
await ddb.putItem(params).promise();
console.log("Success");
} catch (e) {
console.log(e)
}
};
this is my lambda function
This is how my query code look
const getUser = async () => {
const userData = await Auth.currentAuthenticatedUser();
const currentUserId = userData.attributes.sub
await DataStore.query(User, currentUserId).then(setUser);
console.log("getting user in home");
};
useEffect(() => {
getUser();
}, []);

API-gateway-lambda : Cookie not getting saved in browser

I'm trying to know how to use cookies with AWS-Lambda with the serverless framework as per this blogpost
and following is my serverless.yml code
functions:
hello:
handler: handler.hello
events:
- http:
path: /post
method: post
cors:
origin : 'https://xyz.netlify.app'
and Lambda function as per following
"use strict";
const cookie = require("cookie");
module.exports.hello = async (event) => {
const body = JSON.parse(event.body);
const name = body.name;
const value = body.value;
return {
statusCode: 200,
headers: {
"Access-Control-Allow-Origin": "https://xyz.netlify.app",
"Access-Control-Allow-Credentials": true,
"Set-Cookie": cookie.serialize(name, value, {
expires: new Date(new Date().getTime() + 10 * 1000),
}),
},
body: JSON.stringify(
{
input: event,
},
null,
2
),
};
// Use this code if you don't use the http event with the LAMBDA-PROXY integration
// return { message: 'Go Serverless v1.0! Your function executed successfully!', event };
};
As you can notice, I already have configured the code to avoid any cors issue.
While try to send a post request as per following,
const name = document.getElementById('name')
const value = document.getElementById('value')
const post_btn = document.getElementById('post_btn')
post_btn.addEventListener('click', () => {
console.log(name.value, value.value)
const post_url = 'https://abcdxyz59t9.execute-api.ap-south-1.amazonaws.com/dev/post'
const user = {
name: name.value,
value: value.value
};
// request options
const options = {
method: 'POST',
body: JSON.stringify(user),
headers: {
'Content-Type': 'application/json'
}
}
// send POST request
fetch(post_url, options)
.then(res => res.json())
.then(res => console.log(res));
})
I do get a Set-Cookie header like below
But the cookie doesn't get saved in the browser.
That's not the case when I directly try to hit a get request with that URL without the cors in the browser. Can anyone please tell me what to do?

Pre test to automate the access token in Postman

I tried to automate my postman test. In first test I should get access token to execute the API call.
So I write pre test below. But I am getting 'There was an error in evaluating the Pre-request Script:Error: No data, empty input at 1:1 ^'. I tried commenting last section but it's not worked.
How should I automate this ?
const tokenUrl = 'https://xxxxxxxxxxxx/token';
const clientId = 'xxxxxxxxxxxxxxxx';
const clientSecret = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
const getTokenRequest = {
method: 'POST',
url: tokenUrl,
body: {
mode: 'formdata',
formdata: [
{ key: 'grant_type', value: 'Client Credentials' },
{ key: 'client_id', value: clientId },
{ key: 'client_secret', value: clientSecret }
]
}
};
pm.sendRequest(getTokenRequest, (err, response) => {
const jsonResponse = response.json();
const newAccessToken = jsonResponse.access_token;
pm.variables.set('access_token', newAccessToken);
});

Having Issues with external http requests on AWS Lambda

I'm using cities stored in a DynamoDB table to make calls to an external weather API to determine whether it will rain in that city on that day. It then calls a separate Lambda that uses that info to message subscribers of an SNS topic that it will rain.
const AWS = require('aws-sdk');
AWS.config.update({ region: 'eu-west-2' });
const lambda = new AWS.Lambda();
const axios = require('axios');
const tableName = process.env.CITY_TABLE;
const docClient = new AWS.DynamoDB.DocumentClient();
const publishMessageLambda = process.env.PUBLISH_MESSAGE_LAMBDA_NAME;
const weatherApiKey = process.env.WEATHER_API_KEY;
exports.handler = async (event) => {
const scanParams = {
TableName: tableName,
AttributesToGet: ['city'],
};
try {
let citiesArr = await docClient.scan(scanParams).promise();
citiesArr.Items.forEach(async (cityObj) => {
// console.log('cityObj', cityObj);
// console.log('city', cityObj.city);
// console.log('weatherApiKey:', weatherApiKey);
let weatherReport = await axios({
method: 'get',
url: 'http://api.weatherapi.com/v1/forecast.json',
params: {
key: weatherApiKey,
q: cityObj.city,
days: 1,
},
});
// console.log(weatherReport);
let city = cityObj.city;
let dailyChanceOfRain = Number(
weatherReport.data.forecast.forecastday[0].day.daily_chance_of_rain
);
let totalPrecip =
weatherReport.data.forecast.forecastday[0].day.totalprecip_mm;
let lambdaParams = {
FunctionName: publishMessageLambda,
InvocationType: 'RequestResponse',
Payload: JSON.stringify({
body: { dailyChanceOfRain, totalPrecip, city },
}),
};
console.log('dailyChanceOfRain: ', dailyChanceOfRain);
console.log('totalPrecip: ', totalPrecip);
if (dailyChanceOfRain > 50 && totalPrecip > 3) {
let data = await lambda.invoke(lambdaParams).promise();
}
// console.log(
// 'weatherReport: ',
// weatherReport.data.forecast.forecastday[0].day
// );
});
} catch (error) {
console.log(error);
}
};
Running the function locally produces the desired logs on the command line however when running the function on Lambda the logs involving the external http request don't show on the cold start and the logs only show up once the function has been invoked multiple times and often not together.
Any advice would be much appreciated.

Write custom text on existing image in AWS

I need to be able to write some custom text on an image I have, which is stored in S3. What's the best way to do this in the AWS ecosystem?
If possible, I would like to avoid having to start up a server and run PHP or node on it, I would just want use lambda functions or something similar.
Use imagemagick via node.js on Lambda. Lots of people have done this. Here is a good example: https://tech.mybuilder.com/memes-as-a-service-using-lambda-serverless-and-imagemagick/
The lambda function looks like this:
'use strict';
const gm = require('gm').subClass({ imageMagick: true });
const fs = require('fs');
const { IMAGES_DIR, TEXT_SIZE, TEXT_PADDING } = process.env;
const parseText = text => (text || '').toUpperCase();
const getImages = () => fs.readdirSync(IMAGES_DIR);
const parseImage = image => getImages().find(file => file.indexOf(image) === 0);
const random = arr => arr[Math.floor(Math.random() * arr.length)];
const randomImage = () => random(getImages());
module.exports.meme = (event, context, callback) => {
const input = event.queryStringParameters || {};
const top = parseText(input.top);
const bottom = parseText(input.bottom);
const image = parseImage(input.image) || randomImage();
const meme = gm(`${IMAGES_DIR}${image}`);
meme.size(function (err, { height }) {
meme
.font('./impact.ttf', TEXT_SIZE)
.fill('white')
.stroke('black', 2)
.drawText(0, -(height / 2 - TEXT_PADDING), top, 'center')
.drawText(0, height / 2 - TEXT_PADDING, bottom, 'center')
.toBuffer(function (err, buffer) {
callback(null, {
statusCode: 200,
headers: { 'Content-Type': 'image/jpeg' },
body: buffer.toString('base64'),
isBase64Encoded: true,
});
});
});
};