First Invocation of Google Cloud Function always times out - express

I have a google cloud function that's seems to timeout after being inactive for a certain amount of time or if I re-deploy it. Subsequent calls to the end point work just fine, it's just the initial invocation which doesn't work. The following is an over simplified version of what my cloud function is. I basically use an express app as a handler. Perhaps the issue is with the express app not running the first time around, but running on subsequent invocations?
const express = require('express');
const app = express();
const cors = require('cors');
app.use(cors())
app.get('/health', (req, res) => {
res.send('OK');
});
module.exports = app;
Currently have out set to 60s, and a route like the health route shouldn't take that long.
Some interesting log entries
"Function execution took 60004 ms, finished with status: 'timeout'"
textPayload: "Error: Retry total timeout exceeded before any response was received
at repeat (/srv/functions/node_modules/google-gax/build/src/normalCalls/retries.js:80:31)
at Timeout.setTimeout [as _onTimeout] (/srv/functions/node_modules/google-gax/build/src/normalCalls/retries.js:113:25)
at ontimeout (timers.js:436:11)
at tryOnTimeout (timers.js:300:5)
at listOnTimeout (timers.js:263:5)
at Timer.processTimers (timers.js:223:10)"

Cloud Function execution time is limited by the timeout duration, which you can specify at function deployment time. By default, a function times out after 1 minute.
As it is stated in the official documentation:
When function execution exceeds the timeout, an error status is immediately returned to the caller. CPU resources used by the timed-out function instance are throttled and request processing may be immediately paused. Paused work may or may not proceed on subsequent requests, which can cause unexpected side effects.
Note that this period can be extended up to 9 minutes. In order to set the functions timeout limit you can use this gcloud command:
gcloud functions deploy FUNCTION_NAME --timeout=TIMEOUT FLAGS...
More details about your options could be found over here.
But, maybe if your code takes a long time to execute, you may also consider using another serverless option, like Cloud Run.

A Google Cloud Function can be thought of as the event handler for an incoming event request. A cloud function can be triggered from a REST request, pub/sub or cloud storage. For a REST request, consider the function that you supply as the one and only "handler" that the function offers.
The code that you supply (assuming Node.JS) is a function that is passedin an express request object and response object. In the body of the function, you are responsible for handling the request.
Specifically, your Cloud Function should not set up express or attempt to otherwise modify the environment. The Cloud Function provides the environment to be called externally and you provide the logic to be called. Everything else (scaling etc) is handled by Google.

Related

Can't able to call the rest api's asynchoronously

I am new to ios threads. While calling the api in the particular screen its not giving the response until 60 seconds, In between time am calling other api's from same screens or other screens its kept loading. After 60 seconds, it will show the response.
We need to call the asynchronous api's using Alamofire. but its not working
private let alamofireManager : Session
let configuration = URLSessionConfiguration.default
configuration.timeoutIntervalForRequest = 300 // seconds
configuration.timeoutIntervalForResource = 500
alamofireManager = Session.init(configuration: configuration, serverTrustManager: .none)
alamofireManager.request("sample_api",method: .post,parameters: parameters,encoding: URLEncoding.default,headers: nil).responseJSON { (response) in}
First, when getting started it's not necessary to customize anything. Especially when the values you're customizing aren't much different from the defaults.
Second, Alamofire 5.6 now ships with Swift async / await APIs, so I suggest you use those when getting started. You can investigate your network calls without tying them to specific screens until you understand the calls, how they work, and when they should be called.
Third, a 60 second delay sounds like a timeout, as 60 seconds is the default timeout wait. Is that expected? Make sure you have proper access to your server. You should also print your response so you can see what's happening and whether you got data back or an error.
Fourth, use a Decodable type to encapsulate your expected response, it makes interacting with various APIs much simpler. Do not use Alamofire's responseJSON, it's now deprecated.
So you can start your experiment by using Alamofire's default APIs.
let response1 = await AF.request("url1").serializingDecodable(Response1.self)
debugPrint(response1)
let response2 = await AF.request("url2").serializingDecodable(Response2.self)
debugPrint(response2)

HttpContext.Session in Blazor Server Application

I am trying to use HttpContext.Session in my ASP.NET Core Blazor Server application (as described in this MS Doc, I mean: all correctly set up in startup)
Here is the code part when I try to set a value:
var session = _contextAccessor.HttpContext?.Session;
if (session != null && session.IsAvailable)
{
session.Set(key, data);
await session.CommitAsync();
}
When this code called in Razor component's OnAfterRenderAsync the session.Set throws following exception:
The session cannot be established after the response has started.
I (probably) understand the message, but this renders the Session infrastructure pretty unusable: the application needs to access its state in every phase of the execution...
Question
Should I forget completely the DistributedSession infrastructure, and go for Cookies, or Browser SessionStorage? ...or is there a workaround here still utilizing HttpContext.Session? I would not want to just drop the distributed session infra for a way lower level implementation...
(just for the record: Browser's Session Storage is NOT across tabs, which is a pain)
Blazor is fundamentally incompatible with the concept of traditional server-side sessions, especially in the client-side or WebAssembly hosting model where there is no server-side to begin with. Even in the "server-side" hosting model, though, communication with the server is over websockets. There's only one initial request. Server-side sessions require a cookie which must be sent to the client when the session is established, which means the only point you could do that is on the first load. Afterwards, there's no further requests, and thus no opportunity to establish a session.
The docs give guidance on how to maintain state in a Blazor app. For the closest thing to traditional server-side sessions, you're looking at using the browser's sessionStorage.
Note: I know this answer is a little old, but I use sessions with WebSockets just fine, and I wanted to share my findings.
Answer
I think this Session.Set() error that you're describing is a bug, since Session.Get() works just fine even after the response has started, but Session.Set() doesn't. Regardless, the workaround (or "hack" if you will) includes making a throwaway call to Session.Set() to "prime" the session for future writing. Just find a line of code in your application where you KNOW the response hasn't sent, and insert a throwaway call to Session.Set() there. Then you will be able to make subsequent calls to Session.Set() with no error, including ones after the response has started, inside your OnInitializedAsync() method. You can check if the response is started by checking the property HttpContext.Response.HasStarted.
Try adding this app.Use() snippet into your Startup.cs Configure() method. Try to ensure the line is placed somewhere before app.UseRouting():
...
...
app.UseHttpsRedirection();
app.UseStaticFiles();
//begin Set() hack
app.Use(async delegate (HttpContext Context, Func<Task> Next)
{
//this throwaway session variable will "prime" the Set() method
//to allow it to be called after the response has started
var TempKey = Guid.NewGuid().ToString(); //create a random key
Context.Session.Set(TempKey, Array.Empty<byte>()); //set the throwaway session variable
Context.Session.Remove(TempKey); //remove the throwaway session variable
await Next(); //continue on with the request
});
//end Set() hack
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapBlazorHub();
endpoints.MapFallbackToPage("/_Host");
});
...
...
Background Info
The info I can share here is not Blazor specific, but will help you pinpoint what's happening in your setup, as I've come across the same error myself. The error occurs when BOTH of the following criteria are met simultaneously:
Criteria 1. A request is sent to the server with no session cookie, or the included session cookie is invalid/expired.
Criteria 2. The request in Criteria 1 makes a call to Session.Set() after the response has started. In other words, if the property HttpContext.Response.HasStarted is true, and Session.Set() is called, the exception will be thrown.
Important: If Criteria 1 is not met, then calling Session.Set() after the response has started will NOT cause the error.
That is why the error only seems to happen upon first load of a page--it's because often in first loads, there is no session cookie that the server can use (or the one that was provided is invalid or too old), and the server has to spin up a new session data store (I don't know why it has to spin up a new one for Set(), that's why I say I think this is a bug). If the server has to spin up a new session data store, it does so upon the first call to Session.Set(), and new session data stores cannot be spun up after the response has started. On the other hand, if the session cookie provided was a valid one, then no new data store needs to be spun up, and thus you can call Session.Set() anytime you want, including after the response has started.
What you need to do, is make a preliminary call to Session.Set() before the response gets started, so that the session data store gets spun up, and then your call to Session.Set() won't cause the error.
SessionStorege has more space than cookies.
Syncing (two ways!) the sessionStorage is impossible correctly
I think you are thinking that if it is on the browser, how can you access that in C#? Please see some examples. It actually read from the browser and transfers (use) on the server side.
sessionstorage and localstorage in blazor are encrypted. We do not need to do extra for encryption. The same applies for serialization.

Results of S3 function call are being cached by my Lambda function

I have a lambda function that uses S3.listObjects to return a directory listing. The listing is sometimes (not always!) out of date - it doesn't contain recently uploaded objects and has old modification dates for the objects that it does have.
When I run the identical code locally it always works fine.
Clearly some sort of caching but I don't understand where...
Here's the relevant code:
function listFiles() {
return new Promise(function (resolve, reject) {
const params = {
Bucket: "XXXXX",
Prefix: "YYYYY"
};
s3.listObjects(params, function (err, data) {
if (err) reject(err);
else resolve(data.Contents);
});
})
}
That is due to Amazon S3 Data Consistency Model. S3 provides read-after-write consistency for PUTs, however other requests - including listObjects are eventually consistent which means there could be a delay in propagation.
The read-after-write consistency in practice settles in a matter of seconds. It's not a guarantee, however. It's unlikely, but not impossible that amazon returns stale data minutes later, esp if across zones. It's more likely however that your client is caching a previous response for that same URL.
You might have run into a side effect of your lambda container being reused. This is explained at a high-level here. One consequence of container reuse is that background processes, temporary files, and global variable modifications are still around when your lambda is re-invoked. Another article talking about how to guard for it.
If you are sending your logs to cloudwatch logs, you can confirm that a container is being reused if the logs for a lambda seem to be appended to the end of a previous log stream, instead of creating a new log stream.
When your lambda container gets reused, the global variables outside your handler function will be reused. For instance, if you change the loglevel of your logging calls to DEBUG at the end of your handler, if your container gets reused, it will start at the top of the handler in the same loglevel.
If you're using the default s3 client session (it seems like you are), then this connection stays in a global (singleton). If your s3 client connection is reused, it might pull the cached results of calls prior, and I would expect that connection to be reused in a later invocation.
One way to avoid this is to specify the If-None-Match request header. If the ETag of the object you're accessing doesn't match on the remote end, you'll get fresh data. You may set it to the last Etag you got (which you'd store in a global), or alternatively you may try setting a completely random value -- which should act as a cache buster. It doesn't look like list_objects() accepts an If-None-Match header, however. You may try to create a new client session just for the current invocation.
This article on recursive lambdas discusses the issue.

ExpressJs Routing: Could not find official documentation for '_startTime' property in request object

I need to check the time at which request is send to the server. For this I explored the 'req' object. It has a property of '_startTime' which gives me the System time of the Client machine from which request was sent.
I am not able to find the official documentation for this property.
From what I can see, _startTime is not something that Express sets on the request object.
The logger module morgan adds it, but it's convention that properties whose name starts with an underscore are "private": they are for internal use only, and should not be relied upon.
However, it's not very difficult to add such a property yourself. In Express, the most logical method would be to use a middleware function for that:
app.use((req, res, next) => {
req._requestStarted = new Date();
next();
});
Because it's your own application code that sets this property, you can always rely on it existing (as opposed to _startTime which, because it's for internal use by morgan, may be removed or renamed in the future).
To nitpick: this value does not reflect the system time of the client from which the request was sent, it's the time on the server at which the server received the request. In HTTP, clients generally don't send their own local time along with a request.

Morgan not displaying the response time in log

I'm trying to use morgan to log requests for my api server. With my routes configured like this;
app.use logger('dev')
app.use '/api/collab/dataobjects/:do', if config.disable_auth then authMid.noAuthCheck else authMid.authCheck
app.use '/api/collab/dataobjects/:do', queryRouter(config.testing)
app.use '/api/collab/dataobjects/:do', queryRouter()
app.use (req, res, next) ->
console.warn "Test"
err = new Error('Not Found')
err.status = 404
next err
app.use (err, req, res, next) ->
res.status(err.status || 500)
console.warn err
res.send {
message: err.message
error: err
}
Morgan mostly works as expected, but on a few routes gives some nonsense output;
POST /api/collab/dataobjects/1/update - - ms - -
After checking some timings, it was clear that morgan was logging these responses before they had actually been returned. To fix this, I moved the app.use logger('dev') line after the api routes, but before the error catching routes. Placed there, Morgan would display the status code and size of long requests, unlike before, but now on all requests it doesn't show the time it took;
GET /api/collab/dataobjects/1 200 - ms - 4119
Why is Morgan failing to show the response time, and how can I fix it?
I just noticed this question is 2+ years old now, but I've already done the legwork so I'll post my response anyway.
I've seen similar problems myself so I spent a little time digging around to try to figure this out. I'm not sure I can fully answer your question (yet?) but I can explain a few of the things you are seeing:
STARTING THE TIMER:
Morgan starts its timer when the middleware-handler-method (the one with the (req, res, next) signature) is invoked, so in this case:
app.use logger('dev')
app.use '/api/foo/:bar', handler
the reported time should include the time to process /api/foo/:bar, but this case:
app.use '/api/foo/:bar', handler
app.use logger('dev')
it should not include the time to process /api/foo/:bar since the timer starts after the handler method runs.
STOPPING THE TIMER:
Morgan will not stop the timer until it is formatting the log line to be written.
Unless configured otherwise (e.g. with the immediate option), Morgan doesn't write the line to the log until the response has been completely processed, using the on-finished module to get called-back when the express request processing is complete.
REPORTING - INSTEAD OF THE RESPONSE TIME
I think there are a few scenarios that will cause Morgan to write - instead of the response time:
Based on the source code it looks like Morgan will write - to the log when it can't find the temporary variable it set when it "started the timer", therefore writing - to indicate the value is more or less "null".
Morgan also writes - to the log if the request "never" finished processing -- i.e., if the request timed out without completing a valid response. (In this case I guess - more or less indicates "infinity").
Morgan might also write - when the value is literally 0, which might explain why you started seeing - all the time once you moved the app.use(logger) code below your actual routes. Alternatively, since the response is probably already processed by the time Morgan invokes onFinished in your second scenario, the on-finished callback fires immediately, possibly before the temporary start-time variable has been written, leading to #1.
SO WHY DOES MORGAN SOMETIMES WRITE - IN YOUR ORIGINAL SET-UP?
I think the most likely scenario is that your "long-running" requests are timing out according to one part of your infrastructure or another. For example the service that sits in front of your expressjs application (a web server like nginx or an end-user's web browser) will eventually give up on waiting for a response close the connection.
I would need to dig around in the on-finished codebase (or have someone explain this to me :)) to understand what Morgan will get back from on-finished in this scenario, and what it will do with that information, but I think the response time-out is consistent with the information you've shared.