My DataStore is not syncing with DynamoDB for some reason.
I've ready every issue on stackoverflow to see if I can find a resolution but no dice.
There are no errors.
Hub is showing the events firing.
Here is an example of the issue:
try {
const result = await DataStore.save(
new Employer({
name: 'Test Employer',
rate: 123.45,
}),
)
console.log('Employer saved successfully!')
console.log(result)
// const employer = await DataStore.query(Employer)
// console.log('EMPLOYER = ')
// console.log(employer)
} catch (err) {
console.log('ERROR: An error occurred during getEmployer')
console.log('Error message was ' + JSON.stringify(err))
}
DataStore nevers seems to sync with DynamoDB.
Other than that everything is fine. No issues. DataStore contains the correct data.
The only difference between my project and the code examples if that I have used Amplify Studio to build the data model and performed Amplify pull to update the project.
When I do an "amplify status" the API looks correct.
The aws-exports.js file seems to be correct.
It contains entries for Auth, API, Storage etc.
Auth is working correctly.
What am I missing?
Related
In short: Is there some kind of cold start when connecting to Firestore directly from Client SDK
Hey. I'm using Firestore client sdk in Andoid and IOS application through #react-native-firebase.
Everything works perfectly but I have noticed weird behavior I haven't found explanation.
I have made logging to see how long it takes from user login to retrieve uid corresponding data from Firestore and this time has been ~0.4-0.6s. This is basically the whole onAuthStateChanged workflow.
let userLoggedIn: Date;
let userDataReceived: Date;
auth().onAuthStateChanged(async (user) => {
userLoggedIn = new Date();
const eventsRetrieved = async (data: UserInformation) => {
userDataReceived = new Date();
getDataDuration = `Get data duration: ${(
(userDataReceived.getTime() - userLoggedIn.getTime()) /
1000
).toString()}s`;
console.log(getDataDuration)
// function to check user role and to advance timing logs
onUserDataReceived(data);
};
const errorRetrieved = () => {
signOut();
authStateChanged(false);
};
let unSub: (() => void) | undefined;
if (user && user.uid) {
const userListener = () => {
return firestore()
.collection('Users')
.doc(user.uid)
.onSnapshot((querySnapshot) => {
if (querySnapshot && querySnapshot.exists) {
const data = querySnapshot.data() as UserInformation;
data.id = querySnapshot.id;
eventsRetrieved(data);
} else errorRetrieved();
});
};
unSub = userListener();
} else {
if (typeof unSub === 'function') unSub();
authStateChanged(false);
}
});
Now the problem. When I open the application ~30-50 minutes after last open the time to retrieve uid corresponding data from Firestore will be ~3-9s. What is this time and why does it happen? And after I open the application right after this time will be low again ~0.4-0-6s.
I have been experiencing this behavior for weeks. It is hard to debug as it happens only on build application (not in local environments) and only between +30min interval.
Points to notice
The listener query (which I'm using in this case, I have used also simple getDoc function) is really simple and focused on single document and all project configuration works well. Only in this time interval, which seems just like cold start, the long data retrieval duration occurs.
Firestore Rules should not be slowing the query as subsequent request are fast. Rules for 'Users' collection are as follows in pseudo code:
function checkCustomer(){
let data =
get(/databases/$(database)/documents/Users/$(request.auth.uid)).data;
return (resource.data.customerID == data.customerID);
}
match /Users/{id}{
allow read:if
checkUserRole() // Checks user is logged in and has certain customClaim
&& idComparison(request.auth.uid, id) // Checks user uid is same as document id
&& checkCustomer() // User can read user data only if data is under same customer
}
Device cache doesn't seem to affect the issue as application's cache can be cleaned and the "cold start" still occurs
Firestore can be called from another environment or just another mobile device and this "cold start" will occur to devices individually (meaning that it doesn't help if another device opened the application just before). Unlike if using Cloud Run with min instances, and if fired from any environment the next calls right after will be fast regardless the environment (web or mobile).
EDIT
I have tested this also by changing listener to simple getDoc call. Same behavior still happens on a build application. Replacing listener with:
await firestore()
.collection('Users')
.doc(user.uid)
.get()
.then(async document => {
if (document.exists) {
const data = document.data() as UserInformation;
if (data) data.id = document.id;
eventsRetrieved(data);
}
});
EDIT2
Testing further there has been now 3-15s "cold start" on first Firestore getDoc. Also in some cases the timing between app open has been only 10 minutes so the minimum 30 min benchmark does not apply anymore. I'm going to send dm to Firebase bug report team to see things further.
Since you're using React Native, I assume that the documents in the snapshot are being stored in the local cache by the Firestore SDK (as the local cache is enabled by default on native clients). And since you use an onSnapshot listener it will actually re-retrieve the results from the server if the same listener is still active after 30 minutes. From the documentation on :
If offline persistence is enabled and the listener is disconnected for more than 30 minutes (for example, if the user goes offline), you will be charged for reads as if you had issued a brand-new query.
The wording here is slightly different, but given the 30m mark you mention, I do expect that this is what you're affected by.
In the end I didn't find straight answer why this cold start appeared. I ended up changing native Client SDK to web Client SDK which works correctly first data fetch time being ~0.6s (always 0.5-1s). Package change fixed the issue for me while functions to fetch data are almost completely identical.
We are using LocalStack and having issues interacting with DynamoDB using the AWS js SDK. We are getting an "UnknownError" when trying to use the putItem method of the DynamoDB instance. Here is the error output:
{
“name”: “DynamoDbError”,
“data”: {
“dynamoDbPutObjectParameters”: {
“TableName”: “fooTableName”,
“Item”: {
“hello”: {
“S”: “world”
}
}
}
},
“baseError”: {
“message”: null,
“code”: “UnknownError”,
“time”: “2020-11-23T11:40:26.382Z”,
“statusCode”: 500,
“retryable”: true
}
}
We have set the endpoint in the DynamoDB instance options to be:
http://localhost:4566
4566 is the Edge port we have set for the DynamoDB service in LocalStack.
We get validation errors from the SDK if our put object parameters are incorrect BUT these parameters seem to be okay. They DO work on AWS proper when deployed and the table does update.
We have deployed the DynamoDB tables locally using the AWS CDK and aws-cdk-local and WE CAN query, put and update the table in LocalStack using the AWS CLI successfully.
The issue seems to be using the AWS js SDK to interact with the DynamoDB in LocalStack.
Here is the call to putItem which works on AWS but not with LocalStack via the AWS SDK:
putItem: async (
dynamoDbPutObjectParameters
) => {
try {
const data = await dynamoDbInstance.putItem(dynamoDbPutObjectParameters).promise();
return data;
} catch (error) {
throw new DynamoDbError('Failed to put data to DynamoDB', {
data: { dynamoDbPutObjectParameters },
baseError: error
});
}
},
Does anyone have any ideas what might be going on or how to progress?
Thanks
FWIW the issue that was causing the UnknownError was to do with the putItem command parameter. We were not correctly supplying the sortKey value. The LocalStack implementation of DynamoDB does not provide any detailed error output in the response BUT when we tried a similar call on AWS proper we got detailed error output which lead us to understand what was wrong with the implementation.
Its also worth noting that detailed error information did appear in the output of the LocalStack Docker container, just not in the error response when calling the aws js sdk putItem command.
I've been attempting to get to the bottom of issues with a Firebase function I'm using to update some aggregate data in Firestore. I set up a simple test bed and found that any attempt to access the data triggers the error:
> Error: Could not load the default credentials. Browse to https://cloud.google.com/docs/authentication/getting-started for more information.
> at GoogleAuth.getApplicationDefaultAsync (/Users/michael/Documents/htdocs/vue/mjf20/functions/node_modules/google-auth-library/build/src/auth/googleauth.js:160:19)
I've attempted to just copy the entire Firebase config into the initializeApp() function, but it still generates the same error. Here's the entire test code:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
const db = admin.firestore();
exports.postCache = functions.https.onRequest((request, response) => {
console.log("Starting test function");
db.collection('myCollection').doc('myDoc').get()
.then(snap => {
if (!snap.exists) {
console.log('Document not found');
} else {
console.log(snap.data());
response.send(snap.data());
}
})
.catch(error => {
console.log('In catch block');
console.log(error);
response.send(error);
});
});
If I take out the db stuff, the function will work fine. As soon as I add even the simplest firestore request, it generates the error. I've seen this issue asked about before, but the situations seem different, and none of the solutions seems to work. I'm stumped.
The code is perfectly fine.
I have implemented it exactly on my testing project using this tutorial.
I have added your code to index.js and in my firestore I have added collection myCollection with myDoc with just one testing field and deployed using firebase deploy.
Everything works fine. You should focus on your environment and deployment steps to figure out what is the problem. This link that you have in the error is mentioning environment variables. Maybe a case as well.
I hope it will help!
I am working in an android app project for my college minor project. Everything is working but now i want to add a notification feature, i.e whenever a admin posts a notice every user subscriber to that topic gets notification, i tried to follow different tutorials and documents but since i have no programming background in js/nodejs/php i couldn't understand the cloud functions.
Can anyone write the functions or lead me to the answer?
i want the function to be triggered when a new notice is added inside /Notice and send notification to all users subscribe to Notice..
i wrote the following code, after some study,
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.sendNotices =
functions.database.ref('/Notices/{nID}').onCreate((event) => {const data =
event.data;
if(!data.changed()){
console.log('Nothing changed');
return;
}else{
console.log(data.val());
}
const payLoad = {
notification:{
title: 'Message received',
body: 'You received a new message',
sound: "default"
}
};
const options = {
priority: "high",
timeToLive: 60*60*2
};
return admin.messaging().sendToTopic("bctb", payLoad, options);});
and got the error in console of firebase,what am i doing wrong here,
TypeError: Cannot read property 'changed' of undefined
at exports.sendNotices.functions.database.ref.onCreate
(/user_code/index.js:8:13)
at cloudFunctionNewSignature (/user_code/node_modules/firebase-
functions/lib/cloud-functions.js:105:23)
at cloudFunction (/user_code/node_modules/firebase-functions/lib/cloud-
functions.js:135:20)
at /var/tmp/worker/worker.js:770:24
at process._tickDomainCallback (internal/process/next_tick.js:135:7)
Since you are not familiar with the Firebase Cloud Functions, I recommend you first go through official docs here, because without going through the basics you won't understand how they work and then go through Firebase Cloud Messaging (FCM) docs here. Once you get to know how both the service work it'll be a lot easier for you to understand and write your own cloud function. For your ease here is how your function should be like.
You can do this by simply creating an onCreate trigger function. So it will look something like:
exports.SendNotification = functions.database.ref('/Notice/{nid}')
.onCreate((snapshot, context) => {
//Your notification code here
}
Here nid is the notice id that is just created. Firebase will automatically get this id. And for sending the notification you can use Firebase cloud messaging (FCM). In this cloud function you can create a notification payload.
//send notification
const payload = {
data:{
title: "New notice has been added!",
}
};
Now you can send this notification to the app using:
admin.messaging().sendToDevice(instID, payload);
Here, instID is the instance ID. Each app installed has a unique instance ID. For sending to multiple devices you'll have to wrap the code line above in an loop to send notifications to all of the subscribed users. For this you need instance IDs of all the subscribed users.
"I hear and I forget, I see and I remember, I do and I understand"
Best of luck.
I'm able to authorize the Firebase app from my existing Electron app using firebase.auth().signInWithCustomToken. The promise for this method resolves and I'm able to obtain the current authorized user with firebase.auth().currentUser.uid.
At this point I must technically be able to write to /users/<currentUser>. However calling the userRef.set() and userRef.update() methods does not update the database reference and fails silently (both the callback and the promise from these methods do not resolve and there is no error thrown).
What is strange is that the exact same code works in a different, newly created Electron app. My code looks like below:
const writeToFirebase = (customToken) => {
syncApp.auth().signInWithCustomToken(customToken).then(user => {
const userId = firebase.auth().currentUser.uid; // this is successfull
const userRef = firebase.database().ref("/users/" + userId);
userRef.set({data: data}, () => { //callback does not trigger });
userRef.update({data: data})
.then(() => {//promise does not resolve})
.catch(err) => {// promise is not rejected either! }
});
}
Any pointers on how to go about debugging this would be helpful.
I discovered the problem. It's unlikely anybody else would have the same issue, but if you do, take a look at the userAgent value in your browserWindow.loadURL in Electron.
Mine was set to an Android mobile device & Firebase was not setting/updating due to this reason. I presume the Firebase server reacts differently when it sees a mobile userAgent and I was using the Firebase JS SDK and not the Android SDK which caused the issue.