I have a background sync service worker which should call python code to send a message when network access is restored.
Service worker and background sync callback all work correctly (console messages only).
When I add the call to Python I get an Error.
I suspect it is something to do with the code being in Assets/Native Libraries and not in custom Html where most examples calling Python from JS seem to be.
Code Sample: Stored in Assets but registered from code in Native Libraries
self.addEventListener('sync', function(event) {
// debugger
if (event.tag == 'BgSyncMessLater') {
console.log("%cSync Listener called", "color: red;");
event.waitUntil(updateMessages());
}
});
async function updateMessages() {
console.log("%cUpdate Messages func called", "color: red;");
anvil.call(this, 'Send_Messages');
}
Error:
Uncaught (in promise) ReferenceError: anvil is not defined
Clone link:
share a copy of your app
A service worker doesn’t have access to the window namespace. It essentially runs in a different JavaScript context and has no access to the JavaScript context where the app is running apart from via the JavaScript messaging api.
You can read more about that api here: Client: postMessage() method - Web APIs | MDN
/** service worker */
async function postMessage(data) {
const clients = await self.clients.matchAll({
includeUncontrolled: true,
type: "window",
});
for (const c of clients) {
c.postMessage(data);
}
}
/** client (native-libraries or another js file) */
function messageHandler(e) {
const {data} = e;
console.log(data);
// now do some thing - anvil.call is available here since we're in the client
}
navigator.serviceWorker.addEventListener("message", messageHandler)
One thing to keep in mind is that a service worker can outlive its client(s)
e.g. if you lock your phone, the service worker might persist in the background
but the client is no longer available
so no message would be received and the implementation might fall over
You might want to explore anvil-labs experiments with service workers
You can do background/periodic syncs from python code
It’s definitely a wip and not production ready and no documentation 
but it might make things easier 
If you go down this route - definitely start a discussion over at anvil-labs and we can try to point you in the right direction with your use case.
3 Likes
Thanks @stucork.
I decided to keep the code in the service worker by accessing the indexeddb records directly using Javascript and sending the message records to an HTTP endpoint in the Anvil Server code. Just a proof of concept at the minute so no authentication of any sort on the endpoint.
self.addEventListener('sync', function(event) {
if (event.tag == 'BgSyncMessLater') {
console.log("%cSync Listener called", "color: red;");
event.waitUntil(updateMessages());
}
});
function updateMessages() {
console.log("%cUpdate Messages func called", "color: red;");
return getIndexedDB()
.then(sendToServer)
.then(clearSentMessages)
.catch(function(err) {
return err;
})
}
function getIndexedDB() {
console.log("%cgetIndexedDB func called", "color: red;");
return new Promise(function(resolve, reject) {
var db = indexedDB.open('anvil_extras');
db.onsuccess = function(event) {
this.result.transaction("Messages_Store").objectStore("Messages_Store").getAll().onsuccess = function(event) {
resolve(event.target.result);
}
}
db.onerror = function(err) {
reject(err);
}
});
}
function sendToServer(body) {
console.log("%csendToServer func called", "color: red;");
return fetch('https://ccmesstest.anvil.app/_/api/post_messages', {
method: 'POST',
body: JSON.stringify(body),
headers:{
'Content-Type': 'application/json'
}
}).then(function(rez2) {
return rez2.text();
}).catch(function(err) {
return err;
})
}
function clearSentMessages(body) {
console.log("%cclearSentMessages func called", "color: red;", body);
// Delete the rows in indexeddb that match the rows sent to the Endpoint
}
This appears to work so far although the delete sent messages is taking a while (Javascript/promises/indexeddb are all new to me).
Also I spent nearly two days trying to resolve an error message:
Failed to execute 'postMessage' on 'DOMWindow': The target origin provided ('https://anvil.works') does not match the recipient window's origin (............
Which it turns out doesn’t actually stop the code from running - That hurt!!
Can you see any potential issues with the route I’m taking?
You mentioned anvil-labs service workers. What are the pros and cons of using anvil-labs service workers?
here’s a starter example of your app using the anvil-labs service-worker
Hope that helps
Thanks @stucork for this.
Yeah, looks a tiny, tiny bit easier than the method I’m currently using
.
Could you give me a little information about the sync/periodic sync service worker in anvil-labs.
I’m using background sync specifically for the offline/online functionality. ie If I request a background sync and the mobile device is offline then the sync will wait for the device to go back online then the sync will fire irrespective of the alive status of the app.
Is this functionality available with the anvil-labs sync/periodic sync implementation?
Should I be asking this in the labs github discussion section?
Thanks for the input in this. As usual I’m trying to do things way beyond my experience/knowledge level but it sure makes things interesting. 
Yeah the anvil-labs discussion is probably the best place.
But the short answer is that it is a glorified wrapper around what you were already doing.
Doing anvil.server.call in a service worker is a wrapper around doing a fetch to an endpoint in anvil-labs, which in turn calls your server function.
Registering a sync event does what the browser does i.e fires if it’s online, and waits if the app is offline until it’s back online again.
1 Like
Thanks @stucork,
I’m looking forward to trying this out later.

Hi @stucork
I have finally come back to this part of my app and the example app you posted above has stopped working giving an error:
Warning: No method "text_area_1_change" in form Form1: cannot set the 'change' event handler of self.MessageText.
<SERVICE WORKER STDOUT>: Service Worker Loaded
<SERVICE WORKER READY>
Storing Mesage hello
Registering Sync Event
<SERVICE WORKER STDERR>: ExternalError('Error: No Background sync with this name has been created')
ExternalError: Error: No Background sync with this name has been created
at app/anvil_labs/service_worker.py:24
Not sure if its a change to Anvil Labs or with Backgorund Sync itself.
If you have any ideas or pointers I’d be grateful.