Trying a little hack here with cloud functions but can't seem to figure out what the issue is.
I'm currently using now.sh to host serverless functions and would like to call 1 function from another. Lets say I have 2 functions declared fetchData
& setData
. When the setData
function is called it processes some data and then calls the fetchData
function.
export const setData = async (req: Request, res: Response) => {
await axios.post(
fetchDataEndpointUrl,
{
params: {
key,
},
},
);
return res.json({
payload: true,
});
}
The above code works fine but the time taken for the entire operation to plete would be setData function call + the time taken for the fetchData function call to plete. What I'm trying to do is make a call to fetchData
without having to wait for it to plete essentially removing the await
in the axios call. I've tried removing the await
but the call just ends abruptly when the setData
call ends. Is there a way to decouple this action and not have to wait for the setData
function to plete?
Trying a little hack here with cloud functions but can't seem to figure out what the issue is.
I'm currently using now.sh to host serverless functions and would like to call 1 function from another. Lets say I have 2 functions declared fetchData
& setData
. When the setData
function is called it processes some data and then calls the fetchData
function.
export const setData = async (req: Request, res: Response) => {
await axios.post(
fetchDataEndpointUrl,
{
params: {
key,
},
},
);
return res.json({
payload: true,
});
}
The above code works fine but the time taken for the entire operation to plete would be setData function call + the time taken for the fetchData function call to plete. What I'm trying to do is make a call to fetchData
without having to wait for it to plete essentially removing the await
in the axios call. I've tried removing the await
but the call just ends abruptly when the setData
call ends. Is there a way to decouple this action and not have to wait for the setData
function to plete?
-
2
Essentially
setData
is a background task. Im not sure of the infrastructure onnow.sh
but you'll usually implement this with somepub/sub
architecture. I've done something like this onGCP
– C.OG Commented Dec 28, 2019 at 14:16 -
does
setData
accept anext
argument? perhaps returning a response in the first brick of the chain and then calling the axios function in a separate brick would do? more here – shuk Commented Dec 28, 2019 at 14:23 -
@shukar considering this is a serverless architecture, I don't think passing the
next
function over the network would serve any purpose. – Jude Fernandes Commented Dec 28, 2019 at 14:40 - 1 I've done similar things with Firebase Cloud Functions, where I would use a "trigger" HTTPS request, which saves the intended job to Cloud Firestore which triggers a secondary Cloud Function to do the long-running stuff. The benefit of this is that the client can also listen to updates on that Firestore document to get the results – samthecodingman Commented Dec 29, 2019 at 6:09
1 Answer
Reset to default 7The summary of your question appears to be that when you call a Cloud Function, you want it to be able to return a value to its caller while simultaneously performing background work such as calling another service and waiting for a response.
When you return a value to the caller for a Cloud Function, that is the end of the life span of the Cloud Function. You can not be assured of any kind of life in the Cloud Function beyond the return.
This is documented here.
The text (in part) reads:
A function has access to the resources requested (CPU and memory) only for the duration of function execution. Code run outside of the execution period is not guaranteed to execute, and it can be stopped at any time. Therefore, you should always signal the end of your function execution correctly and avoid running any code beyond it.
Another part of the question is what if we want to have our Cloud Function make an asynchronous REST call where we don't care about waiting for the response. Can we return from the Cloud Function without waiting for the nested REST call to plete?
The answer is maybe but it will depend on the nature of service being called and how we are calling it. To appreciate the nuances in this remember that JavaScript is a single threaded language. There aren't multiple threads of execution. In our JavaScript app, only one thing will ever happen at a time. If we make an asynchronous REST call and don't care about a reply but (obviously) do care that the request has been sent then we need to synchronously send the request before we terminate the Cloud Function. This can get tricky if we start using library packages without delving into their natures. For example, a REST call might include:
- A socket connection to the partner
- A transmission of the outbound request
- A callback when the response is received
We need to be absolutely sure that the transmission has happened before we end the top level Cloud Function call. In addition, if we do end the top level Cloud Function call, that may very well tare down the socket used for the response. This could result in an exception in the called REST service that now is unable to return its 200 response.
To run work where we don't need to nor want to wait for a response, GCP provides an architected solution for this. It is called "Cloud Tasks" (see Cloud Tasks). Within your Cloud Function, you would define a request to call your nested service asynchronously and hand that request off to Cloud Tasks to execute. Cloud Tasks would acknowledge receipt of the request to execute and you can now be assured that it will and can return at the highest level.