Difference between clientsClaim and skipWaiting - service-worker

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.

Related

Service Worker file and an offline mode

Do I understand correctly that a server worker file in a PWA should not be cached by a PWA? As I understand, once registered, installed and activated, it exits as an entity separate from a page in a browser environment and gets reloaded by the browser once a new version is found (I am omitting details that are not important here). So I see no reason to cache a service worker file. Browser kind of caching it by storing it in memory (or somewhere). I think caching a service worker file will complicate discovery of its code update and will bring no benefits.
However, if a service worker is not cached, there will be an error trying to retrieve it while refreshing a page that registers it in an offline mode because the service worker file is not available when the network is down.
What's the best way to eliminate this error? Or should I cache a service worker file? What's the most efficient strategy here?
I was doing some reading on PWA but found no clear explanation of the matter. Please help me with your advice if possible.
You're correct. Never cache service-worker.js.
To avoid the error that comes from trying to register without connectivity simply check the connection state from window.navigator.onLine and skip calling register if offline.
You can listen for network state changes and call registration at a later point in time if you want.

Service Worker: pitfalls of self.skipWaiting() and self.clients.claim()

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.

How to stop older service workers?

The image below shows that there are two workers installed - one active and the other not active (just installed).
Register a service worker
Make changes to service-worker.js and reload the page.
The logic is that Service Workers check binary diff and updates the versions of the workers.
So a new service worker is spawned with a new version ID. But why does the old one keeps running ? and How do I close it ?
The sw.js is here https://gist.github.com/boopathi/57b7e8b6d657d55bdc7d
By default, until all tabs that have a page controlled by that old service worker are closed/unloaded, the old service worker will stay running. The new service worker will, well, "wait" in the "waiting" state.
There are options that change this default behavior. They're skipWaiting() and clients.claim().
When skipWaiting() is called from an installing service worker, it will, well, skip the "waiting" state and immediately activate. However, it will not necessarily take control of pages despite being activated—that's what clients.claim() will accomplish.

Best way to run rails with long delays

I'm writing a Rails web service that interacts with various pieces of hardware scattered throughout the country.
When a call is made to the web service, the Rails app then attempts to contact the appropriate piece of hardware, get the needed information, and reply to the web client. The time between the client's call and the reply may be up to 10 seconds, depending upon lots of factors.
I do not want to split the web service call in two (ask for information, answer immediately with a pending reply, then force another api call to get the actual results).
I basically see two options. Either run JRuby and use multithreading or else run several regular Ruby instances and hope that not many people try to use the service at a time. JRuby seems like the much better solution, but it still doesn't seem to be mainstream and have out of the box support at Heroku and EngineYard. The multiple instance solution seems like a total kludge.
1) Am I right about my two options? Is there a better one I'm missing?
2) Is there an easy deployment option for JRuby?
I do not want to split the web service call in two (ask for information, answer immediately with a pending reply, then force another api call to get the actual results).
From an engineering perspective, this seems like it would be the best alternative.
Why don't you want to do it?
There's a third option: If you host your Rails app with Passenger and enable global queueing, you can do this transparently. I have some actions that take several minutes, with no issues (caveat: some browsers may time out, but that may not be a concern for you).
If you're worried about browser timeout, or you cannot control the deployment environment, you may want to process it in the background:
User requests data
You enter request into a queue
Your web service returns a "ticket" identifier to check the progress
A background process processes the jobs in the queue
The user polls back, referencing the "ticket" id
As far as hosting in JRuby, I've deployed a couple of small internal applications using the glassfish gem, but I'm not sure how much I would trust it for customer-facing apps. Just make sure you run config.threadsafe! in production.rb. I've heard good things about Trinidad, too.
You can also run the web service call in a delayed background job so that it's not hogging up a web-server and can even be run on a separate physical box. This is also a much more scaleable approach. If you make the web call using AJAX then you can ping the server every second or two to see if your results are ready, that way your client is not held in limbo while the results are being calculated and the request does not time out.

How to stop a Windows Service programmatically?

I'm writing a simple Windows Service that sends out emails to all employees every month. My question is, how to stop itself when it's done? I'm a noobie in this field so please help me out. Really appreciated.
It will be deployed on the server to be run monthly. I did not start this thing and the code was given to me like that. It is written in VB.NET and I'm asked now to change a few things around it. I noticed that there is only 'Sub OnStart' and wondered when the service would stop? After the main sub is done, what it the status of this service? Is it stopped or just hung in there? Sorry, as I said, I am really new to this....
If you have a task that recurs monthly you may be better off writing a console app, and then using Windows Task Scheduler to set it to run monthly. A service should be used for processes that need to run for a long time or constantly, with or without a user logged on
As every other answer has noted, it sounds like this should be an executable or script that you run as a scheduled task.
However, if you are obligated for some reason to run as a Windows Service and you're working in .NET, you just have to call the Stop() method inherited from ServiceBase once your service completes its work. From the MSDN documentation for the method:
The Stop method sets the service state
to indicate a stop is pending and
calls the OnStop method. After the
application is stopped, the service
state is set to stopped. If the
application is a hosted service, the
application domain is unloaded.
There's one important caveat here: the user account under which the service is running must have permission to stop services (which is a topic for ServerFault).
Once a service's OnStart method completes, it will continue running (doing nothing) until something tells it to stop in one of the following ways:
Programatically, by calling Stop
within the service itself or from an
external process using the method
Colin Gravill describes in his
answer.
Via the command-line.
Through the windows Computer Management console's "Services" panel.
If this is a Win32 service (i.e. written in C or C++), then you simply call SetServiceStatus(SERVICE_STOPPED) and return from ServiceMain.
On the other hand, if you're just sending emails once a month, why are you using a service at all? Use the Windows Task Scheduler and run a normal application or script.
net stop [service_name] ...on the command line will do it too.
But, I agree with everyone else; it seems that Windows Task Scheduler will meet your needs better.
It might be better to write this as a scheduled task, it would certainly be easier to develop initially. Then it would naturally terminate and wouldn't be consuming resources for the rest of the month.
To answer the original question, you can get a list of the current running services in C#
services = System.ServiceProcess.ServiceController.GetServices();
Then look for the one you want and set the status to stopped
locatedService.Status == ServiceControllerStatus.Stopped
Full example on msdn
Is there a reason it has to be a Windows service? If not, then follow #Macros solution. However, if it does, then why stop the service? If you stop it, then it'll just have to be restarted when the emails need to be sent. Based on your description, it doesn't sound like it would require a lot of resources, so I'd suggest just installing it and letting it run, firing up once a month to send the emails.
here's what i did in a similar situation.
windows service runs 24/7 and processes work units. it gets work units through a database view.
table Message
ProcessingStartTime
CompletionDTE
...
the database view only pulls records marked not-complete and have a ProcessingStartTime in the past. So after the service confirms the transaction it executes a stored procedure that updates the database record. For this system, end-user upload excel files to asp.net webfrom that imports them into the database.

Resources