my website refreshs let's say every 5 minutes and I use a service worker. Inside this service worker I use pusher.com and this happens:
There are many "Connection" and "Disconnection" events for only two Clients (Raspberry Pi). After this "Vacated" event there is no re-subscription.
Here is what every site does:
if ('serviceWorker' in navigator) { // Make sure sw are supported
window.addEventListener('load', () => {
navigator.serviceWorker
.register('/sw.js')
.then(reg => {
console.log('Service Worker: Registered');
})
.catch(err => console.log(`Service Worker: Error: ${err}`));
});
}
And this happens only once (and not on activating) in service worker:
var channel = pusher.subscribe('web-' + channel);
const swListener = new BroadcastChannel('swListener');
channel.bind('foo', function() {
self.foo();
});
If I run this code above on every page request everything get worse.
Did I something wrong? Is there a way to check my actual subscriptions in my service worker?
Related
I have a PWA project where I send the data to server. During this process, if the user is offline then the data is stored in indexedDb and a sync tag is registered. So, then when the user comes online that data can sent to the server.
But In my case the sync event gets executed immediately when the we register a sync event tag, which means the data is tried to be sent to server while its offline, which is not going to work.
I think the sync event supposed to fire while its online only, what could be issue here ?
The service worker's sync event works accordingly when I tried to enable and disable the offline option of chrome devtools, and also works correctly in my android phone.
This is how I register my sync tag
function onFailure() {
var form = document.querySelector("form");
//Register the sync on post form error
if ('serviceWorker' in navigator && 'SyncManager' in window) {
navigator.serviceWorker.ready
.then(function (sw) {
var post = {
datetime1: form.datetime1.value,
datetime: form.datetime.value,
name: form.name.value,
image: form.url.value,
message: form.comment.value
};
writeData('sync-comments', post)
.then(function () {
return sw.sync.register('sync-new-comment');
})
.then(function () {
console.log("[Sync tag registered]");
})
.catch(function (err) {
console.log(err);
});
});
}
}
And this is how the sync event is called
self.addEventListener('sync', function (event) {
console.log("[Service worker] Sync new comment", event);
if (event.tag === 'sync-new-comment') {
event.waitUntil(
readAllData('sync-comments')
.then(function (data) {
setTimeout(() => {
data.forEach(async (dt) => {
const url = "/api/post_data/post_new_comment";
const parameters = {
method: 'POST',
headers: {
'Content-Type': "application/json",
'Accept': 'application/json'
},
body: JSON.stringify({
datetime: dt.datetime,
name: dt.name,
url: dt.image,
comment: dt.message,
datetime1: dt.datetime1,
})
};
fetch(url, parameters)
.then((res) => {
return res.json();
})
.then(response => {
if (response && response.datetimeid) deleteItemFromData('sync-comments', response.datetimeid);
}).catch((error) => {
console.log('[error post message]', error.message);
})
})
}, 5000);
})
);
}
});
you mention
The service worker's sync event works accordingly when I tried to enable and disable the offline option of chrome devtools, and also works correctly in my android phone.
So I'm not sure which case is the one failing.
You are right that the sync will be triggered when the browser thinks the user is online, if the browser detects that the user is online at the time of the sync registration it will trigger the sync:
In true extensible web style, this is a low level feature that gives you the freedom to do what you need. You ask for an event to be fired when the user has connectivity, which is immediate if the user already has connectivity. Then, you listen for that event and do whatever you need to do.
Also, from the workbox documentation
Browsers that support the BackgroundSync API will automatically replay failed requests on your behalf at an interval managed by the browser, likely using exponential backoff between replay attempts.
I created a toy mern app which can upload images to mongodb. It works fine in the development but after I deploy to heroku, I get a timeout error. After doing a fair amount of investigations I come to the conclusion that web workers will help sort this out. So I've done this:
This is a snippet from the component that takes care of sending this request, to upload an image:
const handleUploadPhoto = evt => {
evt.preventDefault();
const worker = new Worker('imageUpload.js');
worker.postMessage(selectedPhotos);
worker.onmessage = evt => console.log(evt.data);
closeModal();
};
This whole component is actually a modal, and after I submit this handleUploadPhoto function the modal closes. Notice the closeModal function;
In the same folder as this component I have the imageUpload.js worker file:
self.addEventListener('message', evt => {
const { selectedPhotos } = evt.data;
selectedPhotos.map(photo => {
const formData = new FormData();
formData.append('photo', photo);
fetch( `/api/photo/upload/${JSON.parse(localStorage.getItem('loggedUser'))._id}`, {
method: 'POST',
body: formData,
headers: ['Content-Type', 'multipart/form-data'],
}).then(() => console.log('OK'));
});
self.postMessage(evt.data);
});
The idea behind this functionality is that I select one or more images, then I map through them and send a post request to the server with each image as formData. So I thought to move the request to a worker so that it doesn't break my UI anymore. Needless to say that it doesn't work and it gives net::EMPTY_RESPONSE error after some seconds. What I also noticed is that the worker doesn't communicate with the file it was issued in at all. I tried to make a text message pop in the console:
const handleUploadPhoto = evt => {
evt.preventDefault();
const worker = new Worker('imageUpload.js');
worker.postMessage('Hello');
worker.onmessage = evt => console.log(evt.data);
closeModal();
};
In the same folder as this component I have the imageUpload.js worker file:
self.addEventListener('message', evt => {
self.postMessage(evt.data + ' world');
});
It doesn't work. I tried the same approach in a separate project and it worked.
How can I make an HTTP request do what it's supposed to do from a web worker?
I am writing some end-to-end test cases to test socket connections in my app. I expect receiving socket events after specific rest API requests. For instance, after hitting: /api/v1/[createTag], I expect receiving createTag event to be captured by socket.io-client. The issue is that, it is very inconsistently passing, and sometimes failing, with good rest API requests. The reason to fail is that done() event inside socket.on('createTag' ... is never called, so it gets timeout. On browser, currently all the API endpoints and sockets seem to be working fine. Is there a specific configuration that I might be missing in order to test socket.io-client within Node.js environment and Jest?
Below is my test cases, and thanks a lot in advance:
describe('Socket integration tests: ', () => {
beforeAll(async done => {
await apiInit();
const result = await requests.userSignIn(TEST_MAIL, TEST_PASSWORD);
TEST_USER = result.user;
SESSION = result.user.session;
console.log('Test user authenticated succesfully.');
done();
});
beforeEach(done => {
socket = io(config.socket_host, { forceNew: true })
socket.on('connect', () => {
console.log('Socket connection succesful.');
socket.emit('session', { data: SESSION }, (r) => {
console.log('Socket session successful.');
done();
});
});
})
test('Receiving createTag socket event?', async(done) => {
console.log('API request on createTag');
const response = await Requester.post(...);
console.log('API response on createTag', response);
socket.on('createTag', result => {
console.log('createTag socket event succesful.');
createdTagXid = result.data.xid;
done();
})
});
afterEach(done => {
if(socket.connected) {
console.log('disconnecting.');
socket.disconnect();
} else {
console.log('no connection to break');
}
done();
})
}
Basically, setting event handles after async API calls seems to be the issue. So I should have first set the socket.on( ... and then call rest API.
(30119999.xml in pic1, has a gear mark pre name)
I set this request in Web Worker, response data is ok and I terminated it in onmessage callback
but why the request always in pending and can't preview, please help.
pseudocode:
const workerBlob = new Blob([`onmessage = function (event) {
const xhr = new XMLHttpRequest();
xhr.addEventListener('load', function () {
postMessage(xhr.response);
});
xhr.open('GET', event.data.url, true);
xhr.send();
}`], { type: 'application/javascript' });
const workerURL = URL.createObjectURL(workerBlob);
const worker = new Worker(workerUrl);
worker.postMessage({url});
worker.onmessage = (message) => {
// do something
worker.terminate();
};
According to Debugging Service Workers :
The gear icon signifies that these requests came from the Service
Worker itself. Specifically, these are the requests being made by the
Service Worker's install handler to populate the offline cache.
Make sure you are not terminating your worker too fast. You should terminate the Worker when the loadend event has fired.
I have been using MLab MongoDB and mongoose library to create a db connection inside a serverless (Lambda) handler. It works smoothly on local machine. But sometimes it doesn't work after deployment.The request returns an Internal server error. The weird thing is sometimes it works. But If I remove the database connection code, the handler works. The serverless log just says Process exited before completing request. No real errors so no idea what to do.
The db connection looks like this:
handler.js
// Connect to database
mongoose.connect(process.env.DATABASE_URL, {
useMongoClient: false
}).then((ee) => {
console.log('------------------------invoke db ', ee);
})
.catch(err => console.error('-----------error db ', err));
No error in here too. Any idea what's happening?
When you get Process exited before completing request, it means that the node process has crashed before Lambda was able to call callback. If you go to Cloudwatch logs, there would be an error and stack trace of what happened.
You should connect to the MongoDB instance inside your handler and before you call callback(), disconnect first.
It would be like this...
exports.handler = (event, context, callback) => {
let response;
return mongoose.connect(process.env.DATABASE_URL, {
useMongoClient: false
}).then((ee) => {
// prepare your response
response = { hello: 'world' }
}).then(() => {
mongoose.disconnect()
}).then(() => {
// Success
callback(null, response)
}).catch((err) => {
console.error(err);
callback(err);
})
};
Here is an article explaining with details how lambda work with node and an example of how to implement DB connection.
Differently of #dashmug suggested, you should NOT disconnect your DB since connecting every time will decrease your performance.