Im trying to implement firebase functions v2. however the runtime options i am passing into the onCall function does not seem to work. It is timing out after 60 seconds. Am I doing something wrong here?
const {onCall} = require("firebase-functions/v2/https");
const runtimeOpts = {
timeoutSeconds: 500,
memory: '8GB' as '8GB',
};
export const calculatev2 = onCall(runtimeOpts,
async (event: any) => {
try {
//run calculations
return({calculations: 'the calculated stuffs'});
} catch (err) {
console.log(err.message);
throw new functions.https.HttpsError('internal', 'Error in calculating', err);
}
}
);
⚠ functions: Your function timed out after ~60s. To configure this timeout, see
https://firebase.google.com/docs/functions/manage-functions#set_timeout_and_memory_allocation.
> Error: Function timed out.
> at Timeout._onTimeout (/Users/bic/.nvm/versions/node/v16.13.2/lib/node_modules/firebase-tools/lib/emulator/functionsEmulatorRuntime.js:634:19)
> at listOnTimeout (node:internal/timers:557:17)
> at processTimers (node:internal/timers:500:7)
Related
We've been dealing with this issue in our t3 application for over a week now. Here is the error we are getting in the Vercel function logs:
START RequestId: 3e875969-afce-4409-a7ae-96efc99ff603 Version: $LATEST 2023-01-31T13:43:45.065Z d22a6e7d-0ef6-4aa2-828e-ab70ceb99f02 ERROR Unhandled Promise Rejection {\"errorType\":\"Runtime.UnhandledPromiseRejection\",\"errorMessage\":\"Error: timeout of 3000ms exceeded\",\"trace\":[\"Runtime.UnhandledPromiseRejection: Error: timeout of 3000ms exceeded\",\" at process.<anonymous> (file:///var/runtime/index.mjs:1194:17)\",\" at process.emit (node:events:525:35)\",\" at process.emit (node:domain:489:12)\",\" at emit (node:internal/process/promises:149:20)\",\" at processPromiseRejections (node:internal/process/promises:283:27)\",\" at process.processTicksAndRejections (node:internal/process/task_queues:96:32)\"]} [ERROR] [1675172625066] LAMBDA_RUNTIME Failed to post handler success response. Http response code: 400. RequestId: 3e875969-afce-4409-a7ae-96efc99ff603 Error: Runtime exited without providing a reason Runtime.ExitError END RequestId: 3e875969-afce-4409-a7ae-96efc99ff603 REPORT RequestId: 3e875969-afce-4409-a7ae-96efc99ff603. Duration: 12.50 ms Billed Duration: 13 ms Memory Size: 1024 MB Max Memory Used: 143 MB"
This only happens to Vercel deployed branches.Notice how it says that it is a 3000ms timeout error but the duration is only 12.50ms.
More details:
All necessary variables (like required user id's for API calls) are provided
The failing API calls succeed most of the time but about 1/5 times they fail.
Includes all our API calls
Example failing API call:
import type { NextApiRequest, NextApiResponse } from "next";
import { prisma } from "../../../server/db/client";
export default async function handler(
req: NextApiRequest, res: NextApiResponse) {
if (req.method === "POST") {
try {
const data = JSON.parse(req.body);
const update = await prisma.user.update({
where: { id: data.id },
data: data.data,
});
res.json(update);
} catch (e: any) {
res.status(500).json({ message: e.message });
throw new Error("Could't update user:"+ e.message)
}
}
}
Note:
The error messages in the catch block are printed nowhere.This is more or less how we call all our serverless functions:
async function updateUserCurrentInstitution({ userId, institutionId }) {
const response = await fetch(api.updateUser, {
method: "POST",
body: JSON.stringify({
id: userId,
data: {
currentInstitution: institutionId,
},
}),
});
if (!response.ok) {
throw new Error(response.statusText);
}
return response;
}
Any help would be greatly appreciated !
I switched to NodeJS v18 with the built-in fetch and I'm using it as such:
async function get511AK() {
let res = await fetch(URL, { method: 'GET' })
if (res.ok && (res.headers.get('content-type').includes('json'))) {
let data = await res.json();
jsonresponseAK = data;
} else {
console.log("(" + res.url + ') is not json');
}
}
However, sometimes I'm getting a timeout on the URL, which is going to happen, but it's causing the script to exit. I've tried wrapping this in try/catch and it did not prevent it from exiting.
This never happened in Node v12 under the node-fetch library. What else can I add to control those connection timeouts?
node:internal/deps/undici/undici:11118
Error.captureStackTrace(err, this);
^
TypeError: fetch failed
at Object.fetch (node:internal/deps/undici/undici:11118:11)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
at async Timeout.get511AK [as _onTimeout] (/home/wazebot/dot-scripts/script-relay.js:76:12) {
cause: ConnectTimeoutError: Connect Timeout Error
at onConnectTimeout (node:internal/deps/undici/undici:6625:28)
at node:internal/deps/undici/undici:6583:50
at Immediate._onImmediate (node:internal/deps/undici/undici:6614:13)
at process.processImmediate (node:internal/timers:471:21) {
code: 'UND_ERR_CONNECT_TIMEOUT'
}
}
Node.js v18.12.1
Hope it helped!
process.on('uncaughtException', console.log);
// Uncaught Exception thrown - when you throw an error and did not catch anywhere.
process.on('unhandledRejection', console.log);
// Unhandled Rejection at Promise - similar, when you fail to catch a Promise.reject.
i want to create custom token in cloud function but before that I want to check and compare timestamp from realtime database and with current time.if the timestamp is below 10 min then I want to create custom token and send back to client.please help me to achieve this.i am new to this cloud function firebase.
here is my code
export const authaccount = functions.https.onCall(async (data) => {
try {
const snap= await admin.database().ref("/register/"+data).get();
const time=snap.val().timestamp;
const now=new Date().getDate();
const reg=new Date(time).getDate();
const today=Math.abs(now-reg);
const daydiff=Math.floor(today/1000/60/60/24);
const nowminutes=new Date().getUTCMinutes();
const regminutes=new Date(time).getUTCMinutes();
const timediff=Math.abs(nowminutes-regminutes);
if (timediff<10 && daydiff==0) {
try {
admin.auth().createCustomToken(data).then((customtoken)=>{
console.log("auth created"+" "+timediff+" "+daydiff+" "+customtoken);
return customtoken;
});
} catch (err1) {
throw new functions.https.HttpsError("unknown", err1.message, err1);
}
} else {
console.log("else "+" "+now+" "+reg+" "+time+" "+daydiff);
}
} catch (err2) {
throw new functions.https.HttpsError("unknown", err2.message, err2);
}
});
2:53:20.626 AM
authaccount
Error: Process exited with code 16 at process.<anonymous> (/layers/google.nodejs.functions-framework/functions-framework/node_modules/#google-cloud/functions-framework/build/src/invoker.js:275:22) at process.emit (events.js:314:20) at process.EventEmitter.emit (domain.js:483:12) at process.exit (internal/process/per_thread.js:168:15) at Object.sendCrashResponse (/layers/google.nodejs.functions-framework/functions-framework/node_modules/#google-cloud/functions-framework/build/src/logger.js:37:9) at process.<anonymous> (/layers/google.nodejs.functions-framework/functions-framework/node_modules/#google-cloud/functions-framework/build/src/invoker.js:271:22) at process.emit (events.js:314:20) at process.EventEmitter.emit (domain.js:483:12) at processPromiseRejections (internal/process/promises.js:209:33) at processTicksAndRejections (internal/process/task_queues.js:98:32)
2:53:19.559 AM
authaccount
Error: The caller does not have permission; Please refer to https://firebase.google.com/docs/auth/admin/create-custom-tokens for more details on how to use and troubleshoot this feature. at FirebaseAuthError.FirebaseError [as constructor] (/workspace/node_modules/firebase-admin/lib/utils/error.js:44:28) at FirebaseAuthError.PrefixedFirebaseError [as constructor] (/workspace/node_modules/firebase-admin/lib/utils/error.js:90:28) at new FirebaseAuthError (/workspace/node_modules/firebase-admin/lib/utils/error.js:149:16) at Function.FirebaseAuthError.fromServerError (/workspace/node_modules/firebase-admin/lib/utils/error.js:188:16) at /workspace/node_modules/firebase-admin/lib/auth/token-generator.js:114:53 at processTicksAndRejections (internal/process/task_queues.js:97:5) at async Promise.all (index 1)
2:53:19.558 AM
authaccount
Unhandled rejection
2:53:19.469 AM
authaccount
Function execution took 1386 ms, finished with status code: 200
please help to solve this problem. i don't know where I am making the mistake.
You will need to make sure your Firebase Admin sdk is initiated and running before the function proceeds
if (firebase.apps.length === 0) {
firebase.initializeApp();
}
Resource: https://firebase.google.com/docs/admin/setup#initialize-without-parameters
I doubt you have modified the IAM permissions on your service account but as the comment suggested: https://firebase.google.com/docs/auth/admin/create-custom-tokens#service_account_does_not_have_required_permissions
Once that is confirmed to be working - you will need to ensure that the onCall data is a string and not null, some simple health checks can help you debug your process
console.log(typeof data);
console.warn("Data", data);
from there I would also debug your date times and the realtime database result, these are async and will require the promise to be resolved before you can use it.
Update:
All cloud functions should return a response to the client
onCall uses promises on the client and supports a 'return Object'
example:
return {
token: myCustomToken,
possible: otherValue
};
for comparison, onRequest uses fetch like responses and supports codes
response.status(500)
response.send({name:value})
return;
Source:
https://firebase.google.com/docs/functions/callable#sending_back_the_result
Source:
https://firebase.google.com/docs/functions/http-events#using_express_request_and_response_objects
Update:
all paths and promises need to resolve correctly, this includes awaiting promises to resolve and returning their result or storing the result for any secondary processing - I suggest cleaning up the code, remove the try/catch and use .then().catch()
Example:
if (timediff<10 && daydiff==0) {
return await admin.auth().createCustomToken(data)
.then((customtoken)=>{
console.log("auth created"+" "+timediff+" "+daydiff+" "+customtoken);
return customtoken;
})
.catch (err) {
return new functions.https.HttpsError("unknown", err.message, err);
}
}
else {
console.log("else "+" "+now+" "+reg+" "+time+" "+daydiff);
return "else "+" "+now+" "+reg+" "+time+" "+daydiff;
}
The function of SFTP is working locally and it has the correct configuration.
The problem is with the logs of Lambda that complains about the configuration I believe by giving me an Error: Timed out while waiting for a handshake.
const config = {
host: 'ftp.xxxx.at',
port: '22',
username: 'SFTP_xxx',
password: 'xxx9fBcS45',
MD5_Fingerprint: 'xxx:8f:5b:1a',
protocol: "sftp",
algorithms: {
serverHostKey: ['ssh-rsa', 'ssh-dss']
}
};
// get file
// get sftp file
// here ....
const get = () => {
sftp.connect(config).then(() => {
return sftp.get('./EMRFID_201811210903.csv', null, 'utf8', null);
}).then((stream) => {
let body = stream.on('data', (chunk) => {
body += chunk;
})
stream.on('end', () => {
uploadRFIDsToS3(body)
// close connection
sftp.end()
});
}).catch((err) => {
console.log('catch err:', err)
})
};
-
vpc:
securityGroupIds:
- sg-01c29be1d8fbxx59
subnetdIds:
- subnet-007a88d9xxea434d
-
2019-02-18T13:53:51.121Z e688c7bd-24fc-45a1-a565-f2a4c313f846 catch err: { Error: Timed out while waiting for handshake
at Timeout._onTimeout (/var/task/node_modules/ssh2-sftp-client/node_modules/ssh2/lib/client.js:695:19)
at ontimeout (timers.js:482:11)
at tryOnTimeout (timers.js:317:5)
at Timer.listOnTimeout (timers.js:277:5) level: 'client-timeout' }
I added VPC and Security Group in AWS and I still get the same error.
I ran out of ideas of how to fix it.
Increase the time-out value for the lambda function. The option to allocate more memory and time-out are some of the settings for any lambda function in aws
I figure it out.
What was wrong is that Lambda was actually going to another function without getting the connection established.
So what I did is that I added await to the connection and other functions that should not interfere with each other to make to work.
To understand more about await go to this link:
https://javascript.info/async-await
I am attempting to test this module (receiver.js) for an error thrown:
var request = require('request')
module.exports = function(url){
request({
url: url,
method: 'POST'
}, function(error) {
if(error){
throw error
}
})
}
using this test (test.js):
var test = require('tape')
test('Receiver test', function(t){
var receiver = require('./receiver')
t.throws(function(){
receiver('http://localhost:9999') // dummy url
}, Error, 'Should throw error with invalid URL')
t.end()
})
but tape runs the assertion before the error is thrown, resulting in the following error message:
TAP version 13
# Receiver test
not ok 1 Should throw error with invalid URL
---
operator: throws
expected: |-
[Function: Error]
actual: |-
undefined
at: Test.<anonymous> (/path/to/tape-async-error-test/test.js:5:4)
...
/path/to/receiver.js:9
throw error
^
Error: connect ECONNREFUSED 127.0.0.1:9999
at Object.exports._errnoException (util.js:856:11)
at exports._exceptionWithHostPort (util.js:879:20)
at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1062:14)
Is there a way around this?
Generally, using tape, you have to ensure you call assert.end() after the async call has completed. Using promises (would require request-promise and returning the promise):
test('Receiver test', function(t){
// Tells tape to expec a single assertion
t.plan(1);
receiver('http://localhost:9999')
.then(() => {
t.fail('request should not succeed')
})
.catch(err => {
t.ok(err, 'Got expected error');
})
.finally({
t.end();
});
});
Using async/await:
test('Receiver test', async function(t) {
try {
await receiver('http://localhost:9999');
assert.fail('Should not get here');
} catch (err) {
assert.ok(err, 'Got expected error');
}
t.end();
});
The above example is mostly correct but here's a complete working example that compares async to synchronous side by side and also shows how to check for the error message in a manner similar to the tape examples given on tape's README.md.
test('ensure async function can be tested to throw', async function(t) {
// t.throw works synchronously
function normalThrower() {
throw(new Error('an artificial synchronous error'));
};
t.throws(function () { normalThrower() }, /artificial/, 'should be able to test that a normal function throws an artificial error');
// you have to do this for async functions, you can't just insert async into t.throws
async function asyncThrower() {
throw(new Error('an artificial asynchronous error'));
};
try {
await asyncThrower();
t.fail('async thrower did not throw');
} catch (e) {
t.match(e.message,/asynchronous/, 'asynchronous error was thrown');
};
});