Background sync replaying without background sync event - firefox

I am new to the service workers and trying to develop one to take care of background image uploading. I am using Workbox and firefox for testing. The service worker is loaded and registered correctly and whenever I try to upload an image offline these logs appear in the console:
workbox Request for '/photoUpload' has been added to background sync queue 'PhotoQueue'
workbox Using NetworkOnly to respond to '/photoUpload'
after some seconds before I get online, the following are printed in the log, and the photo is not uploaded to the server:
workbox Background sync replaying without background sync event
workbox Request for '/photoUpload' has been replayed in queue 'PhotoQueue'
workbox All requests in queue 'PhotoQueue' have successfully replayed; the queue is now empty!
here is my serviceWorker.js:
const showNotification = () => {
self.registration.showNotification('Post Sent', {
body: 'You are back online and your post was successfully sent!',
});
};
const bgSyncPlugin = new workbox.backgroundSync.Plugin('PhotoQueue', {
maxRetentionTime: 24 * 60, // Retry for max of 24 Hours
callbacks: {
queueDidReplay: showNotification
}
});
workbox.routing.registerRoute(
new RegExp('/photoUpload'),
new workbox.strategies.NetworkOnly({
plugins: [
bgSyncPlugin
]
}),
'POST'
);
is there a way that I can trigger the background sync event? why the workbox removing the POST request from the Queue before the image is uploaded to the server.

Firefox does not support the Background Sync API natively. workbox-background-sync will attempt to "polyfill" this missing API by automatically retrying the queue whenever the service worker starts up.
Chrome allows you to trigger the background sync event via its DevTools, but as mentioned, Firefox does not. There is no programmatic way to force a service worker to stop and then start again using DevTools in Firefox (as far as I know).
Are you sure that the photo isn't being uploaded to the server? Do you see anything in the Network panel of Firefox's DevTools corresponding to the upload attempt?

Related

Outlook Add-In: AppointmentTimeChanged Event not getting triggered on changing the time of the event

I am trying to listen for any change in timing of the appointment through my Add-In. Here is the code where I am adding the handler.
Office.onReady(function() {
mailboxItem = Office.context.mailbox.item;
console.log("Added event handler");
mailboxItem.addHandlerAsync(Office.EventType.AppointmentTimeChanged, args =>
console.log("AppointmentTimeChanged")
),
args => {
console.log("Listening");
};
});
This however is not working for me.
AppointmentTimeChanged event listener works only till the lifecycle of the add-in. If you are using UI-less add-in functions you will not receive notifications beyond your call to event.completed().
To listen to changes beyond that you will have to listen to change using graph web hooks (https://learn.microsoft.com/en-us/graph/webhooks). This subscription from your backend service will enable you to be notified for event changes even from other clients.
But there is a catch to it, Outlook for MAC does not provide way to listen these changes till the event is sent out. To work around this problem you can use custom properties and listener to changes with these properties. Here is the doc explaining it: https://learn.microsoft.com/en-us/outlook/troubleshoot/calendars/cannot-save-meeting-as-draft-in-outlook-for-mac.

OneSignal registration fails after refresh

I am using OneSignal in my Laravel/Vue app. I have included it within <head> as stated in documentation:
<script src="https://cdn.onesignal.com/sdks/OneSignalSDK.js" async=""></script>
<script>
var OneSignal = window.OneSignal || [];
OneSignal.push(function() {
OneSignal.init({
appId: "{{ env('ONESIGNAL_APP_ID') }}"
});
OneSignal.showNativePrompt();
});
</script>
<script>
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/OneSignalSDKWorker.js')
.then(function () {
console.log('Service worker registered');
})
.catch(function (error) {
console.log('Service worker registration failed:', error);
});
} else {
console.log('Service workers are not supported.');
}
</script>
I also have a service worker of my own, so I've followed the documentation here as well.
What is happening after a hard reset is that service worker gets installed and it is all fine, however once I refresh the page I am getting:
OneSignalPageSDKES6.js?v=151102:1 Uncaught (in promise) InvalidStateError: The current environment does not support this operation.
at Function.getServiceWorkerHref (https://cdn.onesignal.com/sdks/OneSignalPageSDKES6.js?v=151102:1:41510)
at xe. (https://cdn.onesignal.com/sdks/OneSignalPageSDKES6.js?v=151102:1:144028)
at Generator.next ()
at r (https://cdn.onesignal.com/sdks/OneSignalPageSDKES6.js?v=151102:1:716)
And I have no idea what does that mean? What is "current environment"? Where to start debugging? I've tried putting console logs around it, however it led me nowhere...
You would start debugging by looking at the source code of the library.
In your case your library is the OneSignal SDK for browsers.
Let's do this!!!
We can see that this error is thrown by getServiceWorkerHref function (which is defined here) and the error message is driven by the InvalidStateReason enumeration:
case InvalidStateReason.UnsupportedEnvironment:
super(`The current environment does not support this operation.`);
break;
If you look at the first linked file, you will see the note on getServiceWorkerHref OneSignal developers left for the those who dare venture into their source code:
else if (workerState === ServiceWorkerActiveState.Bypassed) {
/*
if the page is hard refreshed bypassing the cache, no service worker
will control the page.
It doesn't matter if we try to reinstall an existing worker; still no
service worker will control the page after installation.
*/
throw new InvalidStateError(InvalidStateReason.UnsupportedEnvironment);
}
As you can see, the error is raised when the service worker has the "Bypassed" state. What is that, you may ask? Let's look at ServiceWorkerActiveState enumeration below, in the same file:
/**
* A service worker is active but not controlling the page. This can occur if
* the page is hard-refreshed bypassing the cache, which also bypasses service
* workers.
*/
Bypassed = 'Bypassed',
It seems, when the browser "hard-refreshes" the page, it bypasses the service worker and OneSignal can't properly initialize when that happens. Hard-refresh can happen for a number of reasons — here are some of them (to the best of my knowledge):
if you click the refresh button a bunch of times (usually seconds consecutive refresh within a short period of time may trigger this)
if you have caching disabled in your DevTools
if the server sets a no-cache header
What is happening after a hard reset
I don't know exactly what you mean by "hard reset", but that sounds like it would trigger this issue. I would suggest you close your browser and then visit the page you are working on without using "reset" functions — theoretically, the service worker should be used for caching on consecutive visits and that would ensure OneSignal can function.

Workbox SW: Runtime caching not working until second Reload

I am new to service worker and workbox. I am currently using the workbox to precache my static assets files, which works fine and I expect my other thirdparty URL to be cached too during runtime, but not working until my second reload on the page:(
Shown Below is the copy of the Code of my Service Worker, please note that I replace my original link to abc.domain.com intentionally :)
workbox.routing.registerRoute(
//get resources from any abc.domain.com/
new RegExp('^https://abc.(?:domain).com/(.*)'),
/*
*respond with a cached response if available, falling back to the network request if it’s not cached.
*The network request is then used to update the cache.
*/
workbox.strategies.staleWhileRevalidate({
cacheName: 'Bill Resources',
maxEntries: 60,
maxAgeSeconds: 30 * 24 * 60 * 60, // 30 Days
}),
);
workbox.routing.registerRoute(
new RegExp('^https://fonts.(?:googleapis|gstatic).com/(.*)'),
//serve from network first, if not availabe then cache
workbox.strategies.networkFirst(),
);
workbox.routing.registerRoute(
new RegExp('^https://use.(?:fontawesome).com/(.*)'),
//serve from network first, if not availabe then cache
workbox.strategies.networkFirst(),
);
I have cleared storage times without number, I refreshed cache storage from google developer tools, but all seems to be the same. Resources from a custom link, google fonts and fontawesome, fail to be cached the first time. Below is the console and the Cache Storage Tab for my page first load image and the second load Image respectively.
Please I dont know what I am doing wrong and why it behaves like so.
Thanks in Advance
This is expected behaviour.
The way service workers get set up is that they will have an install and activate phase, where installation can happen when ever a new service worker is registered or a service worker updates.
A service worker will then activate when it's safe to do so (i.e. no windows are currently being "controlled" be a service worker).
Once a service worker is activated, it'll control any new pages.
What you are seeing is:
Page is loaded and the page registers a service worker
The service worker precaches any files during it's install phase
A service activates but isn't controlling any pages
You refresh the page and at this point the page is controlled and requests will go through the service worker (resulting in the caching on the second load).
The service worker will not cache anything until its been activated. It gets activated only on the second hit itself. To achieve caching on the first hit you have to guide service worker to skip waiting for activation. you can do this by
self.addEventListener('install', () => {
self.skipWaiting(); //tells service worker to skip installing and activate it
/*your code for pre-caching*/
});
once its been skipped it enter the activated mode and will wait for caching but it wont cache the clients interaction. To do so apply the following line
self.addEventListener('activate', () => {
clients.claim();
});
which starts caching on the first hit itself

SignalR 2 - Pending AJX requests after opening multiple tabs

I'm using SignalR 2 and I'm having problems when I open multiple tabs of the same page. After opening 4 or 5 tabs, all the requests get in pending status, like if I had exceeded the maximum allowed by the browser. If I close a few tabs, everything works again. Even with all the tabs opened, if I open a different browser it works. This happens both in Chrome and Firefox. If I disable SignalR, I can open as many tabs as I want.
This is my code:
// Reference the auto-generated proxy for the hub.
notificator.hub = $.connection.messageHub;
// Create a function that the hub can call back to display messages.
notificator.hub.client.refreshNotifications = function () {
// business code
};
$.connection.hub.start().done(function () {
notificator.hubStarted = true;
});
$.connection.hub.disconnected(function () {
notificator.hubStarted = false;
setTimeout(function () {
$.connection.hub.start();
}, 2000); // Restart connection after 2 seconds.
});
If I remove the handler for disconnected event, the problem persists. The notification system works correctly so SignalR is doing its job but it's causing me issues in the app. It's even slower.
I found two solutions:
1) In my case, it's an intranet web application so I know that everybody supports WebSockets and WebSockets doesn't have the connection limitation. But, why this was not working? well, first I added logging to SignalR by adding this line:
$.connection.hub.logging = true;
Then I tried to force using WebSockets:
$.connection.hub.start({ transport: 'webSockets' }).done(function () { .. });
But, checking the logs I found out that WebSockets were not supported because they were not installed in the server. So, I followed these steps in Windows 2012 and installed it:
Open Server Manager.
Under the Manage menu, click Add Roles and Features.
Select Role-based or Feature-based Installation, and then click
Next.
Select the appropriate server, (your local server is selected by
default), and then click Next.
Expand Web Server (IIS) in the Roles tree, then expand Web Server,
and then expand Application Development.
Select WebSocket Protocol, and then click Next.
Click Install.
Source: http://www.iis.net/learn/get-started/whats-new-in-iis-8/iis-80-websocket-protocol-support
After that, everything worked. In Chrome, under Network tab, you'll find a WS filter. Click on it and you should see the websocket.
2) Using IWC-SignalR:
https://github.com/slimjack/IWC-SignalR
It works this way:
One of the windows becomes a connection owner (choosen randomly) and
holds the real SignalR connection. If connection owner is closed or
crashed another window becomes a connection owner - this happens
automatically. Inter-window communication is done by means of IWC.

Implement service on Firefox OS

I'm quite new to Firefox OS. At the moment I'm struggling with implementing some kind of service that listens for geolocation updates in the background.
If there are lots of apps running at the same time mine seems to be killed. While debugging with App Manager it disconnects silently.
I tried requestWakeLock('cpu') and the use of a Worker (as proposed in this thread) but without success.
Background services API isn't implemented, yet and will be available for certified apps only.
I know that there are non-certified apps like ConnectA2 that stay alive all the time so there has to be a way.
Could anybody give me a hint?
Firefox OS doesn't provide a way for you to run a service in the background intentionally, since the classes of the devices that we target (for example, the 128MB device) won't be able to support running apps constantly in the background.
There are alternate ways of implementing these kinds of services though. For example you can use the mozAlarm API in order to wake up your application at specific intervals, or you can use the SimplePush API which allows you to notify your app when a remote server initiates an event.
You can use Alarm API to prevent your app to be killed in the background.
Alarms wakes up the app at fixed intervals.
var alarmId = 0;
function setAlarm() {
function onAlarmAdded() {
alarmId = request.result;
}
var alarmDate = new Date(Date.now() + (60 * 1000)); // 60 seconds later
var request = navigator.mozAlarms.add(alarmDate, "ignoreTimezone");
request.onsuccess = onAlarmAdded;
}
function setHandler() {
function onAlarm(mozAlarm) {
// set next alarm
setAlarm();
}
navigator.mozSetMessageHandler("alarm", onAlarm);
}
function startAlarm() {
setHandler();
setAlarm();
}
function stopAlarm() {
navigator.mozAlarms.remove(alarmId);
}

Resources