Playwright how to wait for couple of requests? - networking

I have a very slow web site which loads couple of requests I'd like to wait for.
Here is an example of my code:
await page.waitForRequest("/api/data/pagesTree1");
await page.waitForRequest("/api/data/pagesTree2");
await page.waitForRequest("/api/data/pagesTree3");
But happens next:
for example pagesTree1 is going, test waits for it, but pagesTree2 and 3 are already here, when second waitForRequest starts, it fails, because the request has arrived already, how can I handle this situation ?
Can I do something like:
await page.waitForRequest(["request1", "request2", ...]);
I mean waiting all of them at the same time.
Or there are other better approaches ?

okay, I can do next:
await Promise.all([
page.waitForResponse(resp => resp.url().includes('/api/data/pagesTree1') && resp.status() === 200),
page.waitForResponse(resp => resp.url().includes('/api/pagesTree2') && resp.status() === 200),
page.waitForResponse(resp => resp.url().includes('/api/pagesTree3') && resp.status() === 200),
]);

Related

Firestore Native Client SDK cold start? (React Native Firebase)

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.

CSS missing in the eyes of Google

When I load the website in a browser, it shows up correctly. However, when testing it with search.google.com it shows up without style sheets (and thereby not passing the test to be suitable for mobile devices). I assume it is because of the service worker I am using. However, I don't know that the problem is with it?
Below is the full code of the service worker in place:
const
_ = {
domain: 'https://matchflix.ch/',
name: 'matchflix'
},
cachable = [_.domain, 'https://fonts.googleapis.com/', 'https://ajax.googleapis.com/'],
log = 'ServiceWorker 1.1'
;
self.addEventListener('fetch', event => {
if(event.request.method !== 'GET')
return;
if(!event.request.referrer.startsWith(_.domain))
return;
if(!cachable.some(url => event.request.url.startsWith(url)))
return;
function versionedURL(request){
switch(request.destination){
case 'image':
case 'script':
case 'style':
let
version = self.serviceWorker.scriptURL.split('?')[1]
;
return new Request(request.url + '?' + version);
default:
return request;
}
}
let
internal = event.request.url.startsWith(_.domain),
request = internal ? versionedURL(event.request) : event.request
;
event.respondWith(caches.open(_.name)
.then(cache => fetch(request)
.then(response => {
console.debug(log, 'Caching', internal, response, request);
if(internal)
cache.put(request, response.clone());
return response;
})
.catch(() => cache.match(request))
)
);
});
This is how the website looks in the eyes of Google:
What I tried so far
Commenting out the registration of the service worker, did not change anything unfortunately.
On search.google.com I saw under more information that there was an unknown error loading the script and style sheets. Unfortunately, no further information was given.
Your site is too slow. The entire page, including all assets needs to load within about 5 seconds so that Googlebot doesn't give up on rendering. I'm opening your site now and the spinner is still going after 30 seconds.

react-native-firebase see if user has an internet connection

I'm trying to upload something to my firestore database, but if the user doesn't have an internet connection it just tries to upload it foreever withour giving me an error.
Is there a way to cancel it when I don't have a connection?
I see two options:
use react-native-netinfo to detect if there's a connection before uploading, something like
NetInfo.fetch().then(({isConnected}) => {
if (isConnected) {
doSomethingWithFirebase();
}
});
Add a timeout to make it fail, like so:
// make it a promise, if it isn't already
const firebaseResult = new Promise(resolve => {
doSomethingWithFirebase()
.then(() => resolve(true))
.catch(() => resolve(false))
})
// resolve after 30s
const timeout = new Promise(resolve => setTimeout(() => resolve(false), 30 * 1000));
const didUpload = await Promise.race([firebasePromise, timeOut]);
I'd personally go with #2, because you can show the user an error (something like "failed to upload. does your connection work?") but it depends what it's for, like if it's analytics data that you don't want them to know about #1 is good for that.
Edit: as OP pointed out, with #2 the action would take place when the connection came back online again, without notice, which may not be desired behavior. You could indicate that there's an open connection somehow, like with an "uploading" icon, and clear it when it finally resolves (with failure or success).

angular5 how to make asyc request?

In my project i made multiple request to server to get data for single page. I want to make all request asyc. Right now until i get the response from first request,the response of second request is not load.
So basically i just want to achive asyc request and response so one request will not wait for other request to finish.
Right now it's like first come first serve fashion.
But i want from multiple request which request get first response should load first.
this is code of my component
constructor(private _dashboardService: DashboardService) {
this.getLineChart();
this.todayPaymentDetails();
this.todayPaymentMethod();
this.rewardCustomers();
this.getAverageBill();
this.getItemByVolumn();
this.getItemBySales();
}
todayPaymentMethod(id=null){
this.paymentMethodsLoader=0;
this._dashboardService.getTodayPaymentMethod(id).subscribe(res =>{
if(null != res.data && '' != res.data){
this.location = res.data.location;
this.payment_methods = res.data.payment_methods;
}
this.paymentMethodsLoader=1;
});
}
this is my service code:
getTodayTotalPayment(id) : Observable<any> {
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers });
return this._http.get(environment.apiUrl + constants.API_V1 + 'today-total-payment/'+id, options)
.map(res => res.json())
.catch((error: any) => Observable.throw(error.json().error || error));
}
Here shows code for only one request but as shown in constructor i send multiple request at a time.
FIrst it is not a good practise to call function like this in constructor.
For running multiple request or observable together use operators i.e. switchMap etc.
Follow this video link related to event loop in JavaScript this will improve your JavaScript execution , event loop concepts . also explains how asynchronous code executed.
Hope it will help.

Fanout on root fails when doing concurrent transaction on unrelated property

The code below shows the minimum example where we see the bug. As you can see, the fanout test/channels/sameKey/chats/${key} while the transaction updates test/user_phone_numbers/${key}.
If I'm understanding transaction and update correctly, these two don't overlap so it should be safe to run concurrently. However, as soon as two concurrent requests come in, Firebug errors out with [Error: set].
'use strict';
const express = require('express');
const server = express();
const firebaseRootRef = new Firebase(process.env.FIREBASE_URL)
const random = max => Math.floor(Math.random() * max)
let key = 0
const nextKey = () => ++key % 2
const fanout = key => {
const fanout = {
[`test/channels/sameKey/chats/${key}`]: random(1000)
}
return firebaseComponent.update(firebaseRootRef, fanout)
}
const transaction1 = key => firebaseRootRef.child('test/user_phone_numbers/' + key)
.transaction(_userId => !_userId ? random(100000) : undefined)
server.get('/', (req, res) =>
transaction1(nextKey())
.then(() => fanout(key))
.then(() => res.send(200))
.catch(e => {console.log(e); res.send(501)})
)
server.listen(3001, function () {
console.log('incoming.controller listening on port 3001!');
});
The apache benchmark command to replicate:
ab -n 1000 -c 2 -r http://localhost:3001/
This isn't a bug, it's working as intended. I ran into this several months back and here's the official response they gave me (emphasis mine).
The issue here are transactions in combination with update calls.
We'll abort any transactions at, below or above the path in any set or
update call. So while the transaction is technically unaffected by
your update call at /venues/1, we still go ahead and cancel the
transaction. We know this is not optimal and we're looking into
improving this with a future release. One workaround is to defer the
update calls until the transactions have completed, or keep the
data in an entirely different subtree. The simplest workaround
might be to move all the writes in the update call into separate set
calls, which will not abort the transaction.

Resources