5

Hot Code Push, step by step

 3 years ago
source link: https://blog.meteor.com/hot-code-push-step-by-step-bd940de7323c
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Hot Code Push, step by step

This is a guest post by Bart Sturm, co-founder of TutorMundi, a Brazilian on-demand tutoring app.

Hot Code Push is one of my favorite features of Meteor.

It’s amazing to be able to push new versions of your app to all users across all devices and platforms at once.

Though as a bridge between several different technologies with many moving parts, it doesn’t always work seamlessly. When you realize it’s not working reliably in your app, what can you do?

Common issues and solutions

Let’s not reinvent the wheel — let’s start with some time-tested solutions:

How to dig deeper

But what if none of these solve your particular issue?

Then let’s start looking at your client side logs.

Of course, you may find the cause of your issue right then and there.

If not, that’s okay — we’re about to start logging a whole lot more. We’re going to follow Hot Code Push every step on the way.

(Note: I shared similar code samples in the Meteor Guide. Also, the libraries Tracker and lodash used here are helpful but not necessary. )

Step 1. Server creates new client hash

Whenever the server thinks the client side may have changed, it calculates a hash of your entire client bundle. We can log the following both on the server and client, and compare:

__meteor_runtime_config__.autoupdate.versions['web.cordova']

Step 2. The client subscribes to new hashes

The server publishes this hash to all clients. The clients subscribe to this publish.

To check the status of our subscription, we can log this in the client:

Meteor.default_connection._subscriptions

This shows lots of information about each of your subscriptions. For more readable output, I like to select the subscription I’m interested in and pick some specific properties. For example:

const { ready, inactive } = _.chain(Meteor)
.get('default_connection._subscriptions', {})
.toPairs()
.map(1)
.find({ name: 'meteor_autoupdate_clientVersions' })
.pick(['inactive', 'ready'])
.value();
console.log(‘ready:’, ready);
console.log(‘inactive:’, inactive);

We can modify this a bit to check the status of the subscription every time the subscription changes (for example, when ready goes from false to true):

const hcpSub = _.chain(Meteor)
.get('default_connection._subscriptions', {})
.toPairs()
.map(1)
.find({ name: 'meteor_autoupdate_clientVersions' })
.value(); // no .pick() this time; return whole object

Tracker.autorun(() => {
hcpSub.readyDeps.depend(); // Rerun when the subscription changes
console.log('hcpSub.ready', hcpSub.ready);
});

Step 3. A new client hash arrives

If the client receives client hashes different from its own, our Cordova app starts downloading the new version. (On web, the download only occurs after the reload; our Meteor app is simply a website after all.)

At this point the reactive Autoupdate.newClientAvailable() will start returning true:

Tracker.autorun(() => {
console.log(Autoupdate.newClientAvailable());
});

Step 4. (Cordova only): the new version was downloaded

On mobile, when the new version is downloaded, Meteor will trigger the callback passed to WebAppLocalServer.onNewVersionReady. There can only be one such callback. To log this step without breaking the next, our code can define a new callback that adds logs and then add the code from the original. At the time of writing, it looks like this:

WebAppLocalServer.onNewVersionReady(() => {
console.log('new version is ready!');
// Copied from original in autoupdate/autoupdate_cordova.js
if (Package.reload) {
Package.reload.Reload._reload();
}
});

Step 5. Ask for permission to reload

The client will now announce that it will reload. The app and packages get a chance to save their data or to deny or delay the reload. To find out if this point is reached, we can add a callback to _onMigrate:

Reload._onMigrate(() => {
console.log('going to reload now');
return [true];
});

Step 6. Reload

If every Reload._onMigrate callback grants permission, the app reloads.

As part of this, all startup callbacks are run again. To know whether a startup was the result of a Hot Code Push or simply of opening the app, we could use a Session variable, which are preserved across Hot Code Push updates:

Meteor.startup(() => {
console.log('Was HCP:', Session.get('wasHCP'));
Session.set('wasHCP', false);

Reload._onMigrate(() => {
Session.set('wasHCP', true);
return [true];
});
});

Going further

Want to know more? The new Hot Code Push article in the Meteor Guide explains this topic in more depth.

Hot Code Push is at its most powerful when you can rely on it without any doubts. I hope these articles help you solve your own Hot Code Push issues so you can speed up your development cycle and focus on serving your customers.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK