Firebase Timestamp in cloud function not displaying time - firebase

I am using this to get the timestamp
admin.database.ServerValue.TIMESTAMP
But in log getting this while doing console the variable
{ '.sv': 'timestamp' }
anyone help me out in this.
Actually i want to get the timestamp then compare it with db timestamp

The admin.database.ServerValue.TIMESTAMP does not contain the actual server-side timestamp, but is merely a marker (the { '.sv': 'timestamp' } that you see). The database server recognizes this marker on write operations, and then writes the server-side timestamp in its place.
This means that you can't get the server-side timestamp without writing to the database. A simple way to see how to get this is:
let ref = firebase.database().ref("test");
ref.on("value", function(snapshot) {
console.log(snapshot.val());
})
ref.set(admin.database.ServerValue.TIMESTAMP)
When you run this code, your log will show three values:
null
This is the current value in the database when you attach the listener with on("value". Here I'm assuming the test node didn't exist yet, so the value would be null.
1573659849577
This is an estimate that the client makes when you the ref.set(...) statement executes. So the client estimates what it thinks the server timestamp may be, and fires a value event. You can use this to update the UI immediately, so that the user doesn't have to wait.
1573659859162
This is the value that the server actually wrote to the database, and then sent back to the client. So this is the actual server-side timestamp that you're looking for.
In theory the client-side estimate (2) and server-side value (3) may be the same, in which case you wouldn't get the third event. But I've never seen that in practice, as they're always off by at least a couple of milliseconds.

Related

Firestore query by server timestamp

Is it possible to filter a Firestore query using the server's timestamp? When trying to perform a query such as:
firebase.app.firestore()
.collection('posts')
.where('timestamp', '<=', firebase.firestore.FieldValue.serverTimestamp())
The following error is thrown.
FirebaseError: Function Query.where() called with invalid data. FieldValue.serverTimestamp() can only be used with update() and set()
I know that I can use new Date() instead of FieldValue.serverTimestamp(), but it would be nice if there was a way to query using the trusted server timestamp. My use case is a collection of discount codes with expiry dates, where the expiry dates are saved as Firestore timestamps. If a user changes their system time this query can potentially return invalid (expired) results if I rely on a client-side date for filtering. I'm using Firebase functions to actually process the discount (where it is easy to validate the expiry using the server timestamp), so users with incorrect system times would still not be able to actually use the discount code. Nonetheless it would be nice to guarantee the time in such a query to never show an expired code in the first place.
FieldValue.serverTimestamp() is a flag, not a real value - it instructs FireeStore to use the current server time as a value during a write operation. It is NOT a true "value" that you can use as a substitute for "now".
What you are thinking of (and want to use) is firebase.firestore.Timestamp.now(), (sp?) https://firebase.google.com/docs/reference/js/firebase.firestore.Timestamp , which uses Epoch time (compensating for timezone). Changing their local clock will NOT defeat this - as you may have noticed elsewhere, most browsers and services (including Firestore) need tot local clock to be fairly accurate to maintain operations. If your user/hacker sufficiently hacks their local clock to try to get around your rules, their Firestore service won't be working anyway.
I've been thinking about a problem similar to yours.
Late reply, but I'll write a solution in hopes that it will help
As you know, "firebase.firestore.FieldValue.serverTimestamp()" cannot be used for querying, and it is very uncertain to query with the device's built-in Timestamp. (e.g. things like currentTimestamp(), Date() )
In this case, the solution may be to use the Security Rule in Firestore.
In my case, I used that method to restrict users.
The "suspesnsions_user" collection is used to limit membership due to fraudulent use of users. (User's membership must be suspended before releasedTimestamp.)
match /suspensions_user/{userId} {
allow read : if request.auth.uid == userId && resource.data.releasedTimestamp > request.time
}
If the Security Rule is used as follows, if the user can access the document located in "suspensions_user/{userId}" through the relevant Security Rule, it can be determined that he is in the status of loss of membership.
Conversely, if the user cannot access the document for reasons such as permission denied , it can be determined that he has normal membership.
As you said in the question, accurate validation is possible if you apply the corresponding Security Rule to a document such as "/coupons/{id}" to validate access to coupons.
Here is what I do to keep my date comparisons accurate:
let timestamp = new Date().toISOString();
// "2021-03-01T11:10:51.392Z"
If you do this in your Firebase Function (or in the client), you'll always get UTC time, in ISO format (ISO 8601).
This is great because you can do simple String comparisons of ISO 8601 date strings.

Lambda as a leaky state machine?

I have a micro-service which involved in an OAuth 1 interaction. I'm finding myself in a situation where two runs of the Lambda functions with precisely the same starting states have very different outcomes (where state is considered the "event" passed in, environment variables, and "stageParameters" from the API Gateway).
Here's a Cloudwatch log that shows two back-to-back runs:
You can see that while the starting state is identical, the execution path changes pretty quickly. In the second case (failure case), you see the log entry "Auth state changed: null" ... that is very odd indeed because in fact this is logged before even the first line of code of the "handler" is executed. Here's the beginning of the functions handler:
export const handler = (event, context, cb) => {
console.log('EVENT:\n', JSON.stringify(event, null, 2));
So where is this premature logging entry coming from? Well, one must assume that it somehow is left over from prior executions. Let me demonstrate ... it is in fact an event listener that was setup in the prior execution. This function interacts with a Firebase DB and the first time it connects it sets the following up:
auth.signInWithEmailAndPassword(username, password)
.then((result) => {
auth.onAuthStateChanged(this.watchAuthState);
where the watchAuthState function is simply:
watchAuthState(user) {
console.log(`Auth state changed:\n`, JSON.stringify(user, null, 2));
}
This seems to mean that when I run the DB a second time I am already "initialized" with the Firebase DB but apparently the authentication has been invalidated. My number one aim is to just get back to a predictive state model and have it execute precisely the same each time.
If, there are sneaky ways to reuse cached state between Lambda executions in resource useful ways then I guess that too would be interesting but only if we can do that while achieving the predictive state machine.
Regarding the logs order, look at the ID that comes after each timestamp at the beginning of each line. I believe this is the invocation ID. In the two lines you have highlighted in orange, they are from different invocations of the function. The EVENT log is the first line to get logged from the invocation with ID ending in 754ee. The Auth state changed: null line is a log entry coming from the earlier invocation of the function with invocation ID ending in c40d5.
It looks like you are setting auth state to null at the end of an invocation, but the Firebase connection is global, so the second function invocation thinks the Firebase connection is already initialized, but then it throws errors because the authentication was nulled out.
My number one aim is to just get back to a predictive state model and
have it execute precisely the same each time.
Then you need to be aware of Lambda container reuse, and not use any global variables.

Firebase.ServerValue.TIMESTAMP returns different value on immediate child_added

I have a Firebase Push with Server Timestamp, where a child_added listener is already listening.
Extremely surprisingly, the value returned to the child_added event is ~300ms different from what is in fact stored in the Firebase Database node. Subsequent reads at the same node, provides the 'correct' time as stored at the node. It is only the initial child_added event that is triggered right when the push is occurring, that is returning a wrong time.
Has anyone observed this issue?
ref = new Firebase(/some/path);
ref.on('child_added', function (childData) {
console.log('childData.pushTime = ' + childData.pushTime);
});
ref.push({pushTime: Firebase.ServerValue.TIMESTAMP});
What the console.log prints is off by ~300ms from what is in fact stored at the path.
The behaviour that you are seeing is the expected behaviour.
It occurs because the child_added event is fired locally, using a value for ServerValue.TIMESTAMP that's determined using the local time and the offset of the local clock from the server clock. However, it's not possible to account for the time it will take for the request to arrive at the server - hence the differing timestamps.
If you also listen to the child_changed event, it will fire with a snapshot that includes the correct time once the write is complete.

Dealing with concurrent requests in Meteor

I'm dealing with a problem where a user can update a document within a specified time limit, and if he doesn't, the server will.
The update involves incrementing a value and adding an object to an array of a document. I need to ensure that only one of the user/server updates the document. Not both.
To ensure this happens, some checks are run to see if the document has already been updated, but there are times where the user and server run at exactly the same time and both pass the checks and then the document is updated twice.
I've been trying many different ways of fixing this, but I haven't been able to. I tried implement a lock similar to this: http://en.wikipedia.org/wiki/Peterson%27s_algorithm to ensure that only one update will happen and the second update will fail, but I haven't been successful. Any ideas?
To ensure this happens, some checks are run to see if the document has already been updated, but there are times where the user and server run at exactly the same time and both pass the checks and then the document is updated twice.
You can achieve this by using a MongoDB update query that simultaneously checks if the value has been updated and updates it. Like this:
var post = Posts.findOne("ID");
// ... do some stuff with the post ...
Posts.update({counter: post.counter}, {$push: {items: newItem}, $inc: {counter: 1}});
As you can see, in one query we both check the counter and increment it - so if two of these queries run one right after another only one will actually update the document (since the counter won't match anymore).

future timestamp as key in firebase

I need to create the notifications for future events. for example similar to reminders. I was thinking that I can use the the server timestamp + future time as the key and than pop only the notifications with the timestamp older than current server time. However I need the server time.
I can't use client side time stamp as it might be out of sync.
Is there a way to get the current time stamp from firebase?
I know that there is a placeholder for timestamp which is replaced on the server side. Can I use this as a key?
I can imagine that probably not so is there a way to listen to this event when the placeholder is replaced with real timestamp?
or generally is there any other sensible method around this problem?
You're probably solving the X/Y problem here, and you might be better off explaining your use case and getting a better overall solution; fetching a server timestamp to use on the client seems extremely likely to be a conceptual problem.
For example, if my goal is just to display the time in messages, I can simple call set, monitor the path, and display what it returns:
var ref = new Firebase(URL);
ref.on('child_added', function(snap) {
// client just listens on path, records have serve timestamp when they arrive
console.log('the last event was added at', snap.val().time);
});
ref.push({ name: 'Kato', time: Firebase.ServerValue.TIMESTAMP });
If you are queuing future events, just store them in a different path and move them to the "present" path when ready. Rather than trying to fetch "now" and insert it later.
If you are set on fetching the timestamp, the simplest way would be to set up a dummy path and set the value against it:
new Firebase(URL).transaction(function(currValue) {
return Firebase.ServerValue.TIMESTAMP;
}, function(err, success, snap) {
console.log('the current server timestamp', snap.val());
});

Resources