My netlify function timeout in production but not in local environment

Hello,

I developed a netlify function who
1 - get a simple string from mongodb
2 - make an external http request
3 - save the resulted data into the previus mongodb database
4 - return the result

My function works like a charm in local. But in production, on netlify, I get always a timeout error.

What can I do to solve it ?

I can’t use background function because I the result of the process directly.
David

@dbconception Is it a timeout on the execution of the function, or on the connection to MongoDB?

Are you able to provide the error message that you see?

Hi @dbconception can you confirm what your site name/slug is?

Hello Nathan, it’s a timeout of the function execution

Hello,
It’s curious-frangipane-4510b3

Hi @dbconception,

Function timeout increase is a Pro and above feature. Let us know once you upgrade, so we can bump the time limit.

1 Like

Hello,

I upgrade to pro on the other account. Can you improve the timeout to 20 secondes please ?

David

hi @dbconception :wave:t6: , thanks so much for reaching back out! I gave you the bump on your function timeout.

Hi Sam0, I still have this error

hi @taahir

did you redeploy your site? You’ve got to do it to make this effective

Hi Gualter,
I just redploy and still have a timeout after 20 secondes.
I don’t understand because as you can see on this screenshot my function end on 1 seconde on local env. But on netlify, it end after 20 secondes…


There seems to be something else here. Given the huge difference, probably our environment cannot connect to your database instance. Can you add more logging to help us understand each step the function takes?

Feel free to share the function contents here if that helps!

I added few logs.

Below my code.

import fetch from 'node-fetch';
import * as dotenv from 'dotenv' // see https://github.com/motdotla/dotenv#how-do-i-use-dotenv-with-import
dotenv.config()
import { MongoClient, ObjectId } from "mongodb";

/**
 * 
 * @param {*} event 
 * @returns true or { statusCode, body }
 */
const middleware = function (event) {
    
    const { AUTH_BASIC } = process.env;
    if(event.httpMethod !== "GET"){
        return {
            statusCode: 400
        }
    }
    if("Basic " + AUTH_BASIC !== event.headers.authorization){
        return {
            statusCode: 401
        }
    }
    return true;
    
}

const renewTokens = async function (refresh_token, client_secret, client_id) {
    const urlSearchParam = new URLSearchParams({
        refresh_token: refresh_token,
        client_id: client_id,
        client_secret: client_secret,
        grant_type: 'refresh_token'
    });

    const options = {
        method: 'POST',
        headers: {'Content-Type': 'application/x-www-form-urlencoded'},
        body: urlSearchParam.toString()
      };
      
    const resp = await fetch('https://oauth.qonto.com/oauth2/token', options)
 
    if(!resp.ok){
        console.error(resp.statusText);
        console.error(await resp.json())
        return null;
    }
    const qontoResponse = await resp.json();

    return qontoResponse;
}

const getCurrentRefreshToken = async function(){
    const { BDD_PWD, BDD_DOCUMENT_ID } = process.env;
    const uri = "mongodb+srv://******:" + BDD_PWD + "@*********cdz.mongodb.net/?retryWrites=true&w=majority"
    const client = new MongoClient(uri);
    let document = null;
    try {
        const database = client.db('taahir_ms');
        const collection = database.collection('qonto_coll');
        // Query for a movie that has the title 'Back to the Future'
        const query = { _id: new ObjectId(BDD_DOCUMENT_ID) };
        document = await collection.findOne(query);
    } finally {
        // Ensures that the client will close when you finish/error
        await client.close();
    }
    if(document && document.refresh_token)
        return document.refresh_token;
    else
        return null;
}

const saveNewRefreshToken = async function(newRefreshToken){
    const { BDD_PWD, BDD_DOCUMENT_ID } = process.env;
    const uri = "mongodb+srv://******:" + BDD_PWD + "@*********mongodb.net/?retryWrites=true&w=majority"
    const client = new MongoClient(uri);
    try {
        const database = client.db('taahir_ms');
        const collection = database.collection('qonto_coll');
        const filter = { _id: new ObjectId(BDD_DOCUMENT_ID)};
        const updateDocument = {
            $set: {
                refresh_token: newRefreshToken
            }
        };
        const result = await collection.updateOne(filter, updateDocument)
    } finally {
        // Ensures that the client will close when you finish/error
        await client.close();
    }
}

exports.handler = async function (event, context) {

    let middlewareResult = middleware(event)
    if (middlewareResult !== true) {
        return middlewareResult
    }
    console.log("middleware ok");

    const { CLIENT_SECRET, CLIENT_ID } = process.env;
    const REFRESH_TOKEN = await getCurrentRefreshToken();
    console.log("get current refresh token ok");
    if(REFRESH_TOKEN === null){
        console.error("can't retrieve the old refresh token")
    }
    const resp = await renewTokens(REFRESH_TOKEN, CLIENT_SECRET, CLIENT_ID);
    console.log("renew token ok");

    if(resp === null || !resp.access_token || !resp.refresh_token){
        console.error("response incomplete or null")
        return {
            statusCode: 500,
            body: "Failed"
        }
    }
    
    const { access_token, refresh_token : new_refresh_token } = resp;
    await saveNewRefreshToken(new_refresh_token);
    console.log("save new token ok");
    
    return {
        statusCode: 200,
        body: JSON.stringify({accessToken : access_token}),
    };
};

thanks. Maybe the issue is a missing environment variable? You’re using them but are you setting them on Netlify?

I add few logs to this function :


const getCurrentRefreshToken = async function(){
    const { BDD_PWD, BDD_DOCUMENT_ID } = process.env;
    const uri = "mongodb+srv://******:" + BDD_PWD + "@cluster0.gcezcdz.mongodb.net/?retryWrites=true&w=majority"
    const client = new MongoClient(uri);
    let document = null;
    try {
        const database = client.db('*****');
        console.log("getCurrentRefreshToken > db ok")
        const collection = database.collection('qonto_coll');
        console.log("getCurrentRefreshToken > coll ok")
        // Query for a movie that has the title 'Back to the Future'
        const query = { _id: new ObjectId(BDD_DOCUMENT_ID) };
        document = await collection.findOne(query);
        console.log("findone ok", document)
    } finally {
        // Ensures that the client will close when you finish/error
        await client.close();
        console.log("getCurrentRefreshToken > client.clos() ok")
    }
    if(document && document.refresh_token)
        return document.refresh_token;
    else
        return null;
}

And got this on function log :


It seems to be the collection.findOne who block.

After checking environement variables, BDD_PWD and BDD_DOCUMENT_ID are well set in netlify. Do you have an idea of why it block ?

Do you have another idea ?

not at this stage, can you try to add logs that output both query and collection:

    try {
        const database = client.db('*****');
        console.log("getCurrentRefreshToken > db ok")
        const collection = database.collection('qonto_coll');
        console.log("getCurrentRefreshToken > coll ok")
        // Query for a movie that has the title 'Back to the Future'
        const query = { _id: new ObjectId(BDD_DOCUMENT_ID) };
        console.log(`query: ${query}`)
         console.log(`collection: ${collection}`)
        document = await collection.findOne(query);
        console.log("findone ok", document)
    }

I got this :


So I added JSON.serialize on your console.log
And now I got :

And

Did you try asking MongoDB why your query can be taking longer:

Unfortunately, without seeing your data structure and debugging this by testing your code, we cannot comment anything beyond this. All this is anyways out of our scope of support.