Test for an active service worker from within the client - client

From within my client.js, I register a service worker with:
var someVariable;
if('serviceWorker' in navigator) {
navigator.serviceWorker.register('./service-worker.js')
.then(function() {
console.log('Service worker registered.');
if(localStorage.someVariable) {
someVariable = JSON.parse(localStorage.someVariable);
};
});
};
Now, further down my client.js code, I would like to check whether client.js has an active service worker up and running.
Doing so from within service-worker.js would somewhat correspond to testing for self.registration, as self.registration.active does not seem to work.
However, what would be the equivalent test for an active service worker from within client.js?
navigator.serviceWorker.ready retuns a Promise, but I do not know if this is really what I need for use in/as a conditional.

Your options
If you want to check whether the current page is under the control of some service worker at the current moment, you can examine navigator.serviceWorker.controller. It will be null if the current page is not controlled by a service worker, and set to a ServiceWorker instance if it is controlled by one.
If you want to check if the service worker associated with a given ServiceWorkerRegistration is active at a given point in time, you can do that with code like:
const registration = await navigator.serviceWorker.register('sw.js');
// Examine `registration.active` to see if, at the current point in time,
// there's an active service worker.
If you want to write code that will wait until there's any active service worker associated with the current page's service worker registration, then await navigator.serviceWorker.ready will do that for you.
active vs. controlling
Just a quick note on the difference between an active service worker, and a controlling service worker. A service worker can be active but not in control of any client pages—this is what would happen the first time a service worker is registered for a given scope if the service worker doesn't call clients.claim().
If you are calling clients.claim() in your service worker, then the distinction between active and controlling can mostly be ignored.

Related

Async feature in Servlets

I was just going back to Servlet-3.x features and exploring it. If I am not wrong, before Servlet-3.x it was thread per request model and it would run out of threads in the pool, for heavy incoming traffic.
So, with Servlet-3.x it says it is Asynchronous and doesn't keep the threads blocked , rather releases them immediately but just the task is delegated.
Here is my interpretation,
consider there are 2 threads in Server thread-pool
For a new Async Servlet request R1 there is a thread T1, this T1 would delegate the task to T2 and T1 responds back to client immediately.
Question: Is T2 created from Server thread-pool? If so, I don't get the point.
Case 1: If it was old Synchronous Servlet request T1 would have been busy running I/O task,
Case 2: If it was Asynchronous Servlet call T2 is busy running I/O task.
In both cases, one of them is busy.
I tried to check the same with a sample Async servlet in openliberty app server, below is the sample log captured from my sample demo Servlet.
Entering doGet() == thread name is = Default Executor-thread-116
Exiting doGet() == thread name is = Default Executor-thread-116
=== Long running task started ===
Thread executing #start of long running task = Default Executor-thread-54
Thread executing #end of long running task = Default Executor-thread-54
=== Long running task ended ===
As shown above, the Default Executor-thread-116 is released immediately and delegated long running task to the Default Executor-thread-54, but I am not sure if they are from the App Server thread pool. If so, why can't just Default Executor-thread-116 do the task instead of delegation?
Can someone throw some light on this async behavior of Servlets in JavaEE
In your example, where the work is synchronous and there's no separate executor/threadpool, there is nearly no point to use async servlets. Lots of samples/examples out there are just block on a 2nd thread because they're trying to illustrate just the syntax.
But there's no reason why you can't spin off a thread to do a little work, add your async context to some list, and then after some event (inbound JMS, websocket, whatever) provides the data needed to complete the async response. For example, a 2-player game server wouldn't wait for player 2 in a second thread, it would just have their async context floating around in memory waiting for a 2nd player to find it.

Azure, SubscriptionClient.OnMessage, and Sessions

Does the Azure Service Bus Subscription client support the ability to use OnMessage Action when the subscription requires a session?
I have a subscription, called "TestSubscription". It requires a sessionId and contains multipart data that is tied together by a SessionId.
if (!namespaceManager.SubscriptionExists("TestTopic", "Export"))
{
var testRule = new RuleDescription
{
Filter = new SqlFilter(#"(Action='Export')"),
Name = "Export"
};
var subDesc = new SubscriptionDescription("DataCollectionTopic", "Export")
{
RequiresSession = true
};
namespaceManager.CreateSubscription(sub`enter code here`Desc, testRule);
}
In a seperate project, I have a Service Bus Monitor and WorkerRole, and in the Worker Role, I have a SubscriptionClient, called "testSubscriptionClient":
testSubscriptionClient = SubscriptionClient.CreateFromConnectionString(connectionString, _topicName, CloudConfigurationManager.GetSetting("testSubscription"), ReceiveMode.PeekLock);
I would then like to have OnMessage triggered when new items are placed in the service bus queue:
testSubscriptionClient.OnMessage(PersistData);
However I get the following message when I run the code:
InvalidOperationException: It is not possible for an entity that requires sessions to create a non-sessionful message receiver
I am using Azure SDK v2.8.
Is what I am looking to do possible? Are there specific settings that I need to make in my service bus monitor, subscription client, or elsewhere that would let me retrieve messages from the subscription in this manner. As a side note, this approach works perfectly in other cases that I have in which I am not using sessioned data.
Can you try this code:
var messageSession=testSubscriptionClient.AcceptMessageSession();
messageSession.OnMessage(PersistData);
beside of this:
testSubscriptionClient.OnMessage(PersistData);
Edit:
Also, you can register your handler to handle sessions (RegisterSessionHandler). It will fire your handle every new action.
I think this is more suitable for your problem.
He shows both way, in this article. It's for queue, but I think you can apply this to topic also.

Open Sockjs inside an application

I want to create an application where on page3 users start communicating via a sockjs websocket (they go through page1 and page2 to reach page 3). The code is working fine but I dont know why!
// Global scope
var sock;
// Inside a function page3, this is invoked when Page3 loads for the first time
function page3(){
// Local scope
sock= new SockJS("localhost:8080/messages);
sock.onopen= function(){
....
};
sock.onmessage= function(data){
....
};
}
My question is - when a message is sent from the server how is sock.onmessage accessed by program execution even though it is 'seen' only when Page3 is loaded the first time which is when function page3() is called?
Looks like sock is not imported (the error message is saying that it is whats undefined)
Perhaps if you could share more of the code we could see why
Found my own answer.
The question is actually related to visibility of event listeners on the client. And the answer to that is - all event listeners on the client, once activated (flow of program execution having "seen" them) remain active until they are removed.
So in the above case, even though function page3() was "seen" by program execution only once - when Page3 was loaded for the first time, sock.onmessage becomes activated as a (client) event listener during that page3() function call and continues to remain active until the socket is closed.
As such, there is no need for an explicit page3() function call to trigger sock.onmessage. It (sock.onmessage) will keep listening to socket events sent by the server.

Using Sessions in synchronous Request-Response patterns

I am trying to get sessions to work in the following architecture.
Multiple heterogenous worker roles that monitor and process requests from queue1, and send their responses to queue2.
One front web role, which receives requests from outside via REST or SOAP, submits them into queue1, and waits for a response from queue2. Once it's received, the response is returned to the caller.
The web role is there to leverage scalability and allow the worker roles to be created dynamically when the load is too high (which is why the entire Ruth Goldberg machine, there is no way without the service bus).
I am using a call to:
MessageSession sess = myQueueClient.AcceptMessageSession(mySessionId, TimeSpan.FromSeconds(timeoutPerSec));
which is followed by:
BrokeredMessage bm = sess.Receive();
and the call to AcceptMessageSession crashes and burns with the exception:
BR0012A sessionful message receiver cannot be created on an entity that does not require sessions. Ensure RequiresSession is set to true when creating a Queue or Subscription to enable sessionful behavior.
Now I do set RequiresSession to true:
if (!_queueManager.QueueExists(clientID))
_queueManager.CreateQueue(clientID).RequiresSession = true;
else
_queueManager.GetQueue(clientID).RequiresSession = true;
but it does not help.
What am I doing wrong?
You have to create a queue with RequiresSession set to true in QueueDescription when you create a queue, not in a QueueDescription of already created queue.
So you in your case queue creation should look similar to this:
if (!_queueManager.QueueExists(clientID))
{
QueueDescription queueDescription = new QueueDescription(clientID)
{
RequiresSession = true
};
_queueManager.CreateQueue(queueDescription);
}

Spring #Async cancel and start?

I have a spring MVC app where a user can kick off a Report generation via button click. This process could take few minutes ~ 10-20 mins.
I use springs #Async annotation around the service call so that report generation happens asynchronously. While I pop a message to user indicating job is currently running.
Now What I want to do is, if another user (Admin) can kick off Report generation via the button which should cancel/stop currently running #Async task and restart the new task.
To do this, I call the
.. ..
future = getCurrentTask(id); // returns the current task for given report id
if (!future.isDone())
future.cancel(true);
service.generateReport(id);
How can make it so that "service.generateReport" waits while the future cancel task kills all the running threads?
According to the documentation, after i call future.cancel(true), isDone will return true as well as isCancelled will return true. So there is no way of knowing the job is actually cancelled.
I can only start new report generation when old one is cancelled or completed so that it would not dirty data.
From documentation about cancel() method,
Subsequent calls to isCancelled() will always return true if this method returned true
Try this.
future = getCurrentTask(id); // returns the current task for given report id
if (!future.isDone()){
boolean terminatedImmediately=future.cancel(true);
if(terminatedImmediately)
service.generateReport(id);
else
//Inform user existing job couldn't be stopped.And to try again later
}
Assuming the code above runs in thread A, and your recently cancelled report is running in thread B, then you need thread A to stop before service.generateReport(id) and wait until thread B is completes / cancelled.
One approach to achieve this is to use Semaphore. Assuming there can be only 1 report running concurrently, first create a semaphore object acccessible by all threads (normally on the report runner service class)
Semaphore semaphore = new Semaphore(1);
At any point on your code where you need to run the report, call the acquire() method. This method will block until a permit is available. Similarly when the report execution is finished / cancelled, make sure release() is called. Release method will put the permit back and wakes up other waiting thread.
semaphore.acquire();
// run report..
semaphore.release();

Resources