I want my service worker to get the height and width of the screen.
I've tried screen.height, self.innerHeight, window.innerHeight, but it seems service workers run on a different context where these are undefined.
Is there a way to access device information like height and width within the context of a service worker?
Service Workers (and all workers in general) can't access the DOM.
I can see two ways to achieve what you want:
Store those values in IndexedDB (or in a Cache) in your page and access them in the worker;
Send those values from the page to the service worker using postMessage.
Obviously, you can use the first solution always, you can't use the second solution when your service worker is running and there isn't any page open.
Related
I have a web application. The cold start time of the backend service is about 10 second which is very high. I was not able to reduce the cold start time. As a second solution, I am wondering if can requests that makes cloud run service scale up handled by already running instances. After the new scaled containers ready, new requests will be handled by scaled up containers. Does Google Cloud support that?
You have a brand new feature for that. It's Health Probe you can put on your service to detect when the instance is ready to serve traffic, or unhealthy and no new request will be routed to it.
Have a try on it, it should solve your issue!
As a second solution, I am wondering if can requests that makes cloud run service scale up handled by already running instances.
I think what you really want is min-instances. This means you always will have an instance that is ready to serve requests.
Otherwise, I don't think there is any solution that would solve the problem that you have. If new requests come in, you are going to need to scale up either way, and there is nothing around the 10 second cold start. So implement min-instances with a base-line that is appropriate for your traffic.
I'm currently seeing delays of 2-3 seconds on my first requests coming into our APIs.
We've set the min instances to 1 to prevent cold start but this a delay is still occurring.
If I check the metrics I don't see any startup latencies in the specified timeframe so I have no insights in what is causing these delays. Tracing gives the following:
The only thing I can change, is switching to "CPU is always allocated" but this isn't helping in any way.
Can somebody give more information on this?
As mentioned in the Answer :
As per doc :
Idle instances As traffic fluctuates, Cloud Run attempts to reduce the
chance of cold starts by keeping some idle instances around to handle
spikes in traffic. For example, when a container instance has finished
handling requests, it might remain idle for a period of time in case
another request needs to be handled.
Cloud Run But, Cloud Run will terminate unused containers after some
time if no requests need to be handled. This means a cold start can
still occur. Container instances are scaled as needed, and it will
initialize the execution environment completely. While you can keep
idle instances permanently available using the min-instance setting,
this incurs cost even when the service is not actively serving
requests.
So, let’s say you want to minimize both cost and response time latency
during a possible cold start. You don’t want to set a minimum number
of idle instances, but you also know any additional computation needed
upon container startup before it can start listening to requests means
longer load times and latency.
Cloud Run container startup There are a few tricks you can do to
optimize your service for container startup times. The goal here is to
minimize the latency that delays a container instance from serving
requests. But first, let’s review the Cloud Run container startup
routine.
When Starting the service
Starting the container
Running the entrypoint command to start your server
Checking for the open service port
You want to tune your service to minimize the time needed for step 1a.
Let’s walk through 3 ways to optimize your service for Cloud Run
response times.
1. Create a leaner service
2. Use a leaner base image
3. Use global variables
As mentioned in the Documentation :
Background activity is anything that happens after your HTTP response
has been delivered. To determine whether there is background activity
in your service that is not readily apparent, check your logs for
anything that is logged after the entry for the HTTP request.
Avoid background activities if CPU is allocated only during request processing
If you need to set your service to allocate CPU only during request
processing, when the Cloud Run service finishes handling a
request, the container instance's access to CPU will be disabled or
severely limited. You should not start background threads or routines
that run outside the scope of the request handlers if you use this
type of CPU allocation. Review your code to make sure all asynchronous
operations finish before you deliver your response.
Running background threads with this kind of CPU allocation can create
unpredictable behavior because any subsequent request to the same
container instance resumes any suspended background activity.
As mentioned in the Thread reason could be that all the operations you performed have happened after the response is sent.
According to the docs the CPU is allocated only during the request processing by default so the only thing you have to change is to enable CPU allocation for background activities.
You can refer to the documentation for more information related to the steps to optimize Cloud Run response times.
You can also have a look on the blog related to use of Google API Gateway with Cloud Run.
Im trying to understand the difference between skipWaiting and clientsClaim. In my understanding: calling skipWaiting will cause the new service worker to skip the waiting phase, and become active right away. clientsClaim can then 'claim' any other open tabs as well.
What I gather from documentation online:
skipWaiting skips the waiting phase, and becomes active right away source
clientsClaim immediately start controlling pages source
In every post I find online, I usually always see clientsClaim and skipWaiting used together.
However, I recently found a service worker that only uses clientsClaim, and I'm having a hard time wrapping my head around what actually is the difference between clientsClaim and skipWaiting, and in what scenario do you use clientsClaim but not skipWaiting?
My thinking on this, and this may be where I'm wrong, but this is my understanding of it:
Is that calling clientsClaim, but not skipWaiting is redundant? Considering:
The new service worker will become active when all open pages are closed (because we're not using skipWaiting)
When our new service worker is activated, we call clientsClaim, even though we just closed all open pages to even activate the new service worker. There should be no other pages to control, because we just closed them.
Could someone help me understand?
Read documentation on skipWaiting
Read documentation on clientsClaim
Read about service worker lifecycle by Jake Archibald, and played around with this demo
Read a bunch of stackoverflow posts, offline cookbook, different blog posts, etc.
self.skipWaiting() does exactly what you described:
forces the waiting service worker to become the active service
"Active" in this sense does not mean any currently loaded clients are now talking to that service. It instead means that service is now the service to be used whenever a new client requests it.
This is where Clients.claim() comes in:
When a service worker is initially registered, pages won't use it until they next load.
Without calling claim, any existing clients will still continue to talk to the older service worker until a full page load.
While most of the time it makes sense to use skipWaiting and Clients.claim in conjunction, that is not always the case. If there is a chance of a poor experience for the user due to a service worker not being backwards compatible, Clients.claim should not be called. Instead, the next time a client is refreshed or loaded, it would now have the new service worker without worry of the breaking change.
The difference between skipWaiting() and Clients.claim() in Service Workers
An important concept to understand is that for a service worker to become operational on a page it must be the controller of the page. (You can actually see this property in Navigator.serviceWorker.controller.) To become the controller, the service worker must first be activated, but that's not enough in itself. A page can only be controlled if it has also been requested through a service worker.
Normally, this is the case, particularly if you're just updating a service worker. If, on the other hand, you're registering a service worker for the first time on a page, then the service worker will be installed and activated but it will not become the controller of the page because the page was not requested through a service worker.
You can fix this by calling Clients.claim() somewhere in the activate handler. This simply means that you wont have to refresh the page before you see the effects of the service worker.
There's some question as to how useful this actually is. Jake Archibald, one of the authors of the spec, has this to say about it:
I see a lot of people including clients.claim() as boilerplate, but I rarely do so myself. It only really matters on the very first load, and due to progressive enhancement the page is usually working happily without service worker anyway.
As regarding its use with other tabs, it will again only have any effect if those tabs were not requested through a service worker. It's possible to have a scenario where a user has the same page open in different tabs and has these tabs open for a long period of time, during which the developer introduces a service worker. If the user refreshes one tab but not the other, one tab will have the service worker and the other will not. But this scenario seems somewhat uncommon.
skipWaiting()
A service worker is activated after it is installed, and if there is no other service worker that is currently controlling pages within the scope. In other words, if you have any number of tabs open for a page that is being controlled by the old service worker, then the new service worker will not activate. You can therefore activate the new service worker by closing all open tabs. After this, the old service worker is controlling zero pages, and so the new service worker can become active.
If you don’t want to wait for the old service worker to be killed, you can call skipWaiting(). Normally, this is done within the install event handler. Even if the old service worker is controlling pages, it is killed anyway and this allows the new service worker to be activated.
Is there a simple way to create an istance of a docker container for each request?
I have a Docker container that takes a very long time to compute a mathematical algorithm. When running, no other requests can be processed in parallel. Lambda Functions would be the best solution, but the container needs to download more than 1gb of data and needs at least 10 cores and 5GB ram to be executed, and therefore Lambda would be too expensive.
We have a big cluster (1000 cores, 0.5TB RAM) and I was considering to use a NGINX Load balancer or a Kubernetes bare metal.
Is it possible to configure in a way that creates an instance per request (similar to a Lambda Function)?
There are tools like Airflow or Argo that are designed for these things.
basically you can create a DAG will run very much like a function as a service but on what ever custom docker container you want.
You probably need to decouple the HTTP service from the backend processing. If the job takes minutes or longer to run, most browsers and other HTTP clients will time out before it will finish, so the HTTP end of it needs to start the job in some way and immediately return some sort of success message.
Once you’ve done that, you might find a job queue like RabbitMQ a useful piece of infrastructure technology. Again, this decouples the queue of jobs from the mechanism to actually run them. In a Docker/Kubernetes space you’d launch some number of persistent workers that all listened to the queue and did work as it appeared there. You wouldn’t necessarily launch one worker per job; or possibly you would have just one worker that launched other Docker containers or Kubernetes Jobs; but if the work backlog got too long you could launch additional workers.
In a pure-Docker space it’s theoretically possible to use the Docker API to launch additional containers. However, doing this gives your process unlimited root-level access to the host; if you are running this in the context of an HTTP server you need to be extremely careful about security considerations. Kubernetes also has an API and from a security point of view this is probably better: you can set up a service account that has permissions only to launch Jobs, and launch a Job per inbound job that arrives. (Security is still important but it’s much harder for a malicious input to root the host.)
To immediately activate a service worker after it's installed, I use self.skipWaiting() in the install listener. To immediately take control of a page (without the need for a page navigation, e.g. page load), I use self.clients.claim(). I understand that doing such things means:
Page could first load without it being under the control of a Service Worker, but then be taken over by a Service Worker during its lifespan.
A page could start under the control of version 1 of Service Worker but then be taken over by version 2 during its lifespan.
There are all kinds of warnings online about doing such things, but I don't see the pitfalls. Perhaps one potential problem is if the controlled page does some initial handshake or setup with a Service Worker when it first loads. That obviously will be missed when the new Service Worker activates in the background, but even then, the Service Worker could message its controlling pages to notify them of the change.
It seems to me that for most applications under most scenarios would benefit significantly by using both self.skipWaiting() and self.clients.claim() without any downside. Did I miss something?
The pitfalls of self.skipWaiting() is described really well here (thanks #RobertRowntree for the link):
https://redfin.engineering/how-to-fix-the-refresh-button-when-using-service-workers-a8e27af6df68
As for self.clients.claim(), I still haven't seen a compelling argument against it, but when I do, I'll update my answer.