mirror of
https://github.com/meteor/meteor.git
synced 2026-05-02 03:01:46 -04:00
allow packages to block migration until they're ready
This commit is contained in:
@@ -97,14 +97,14 @@ Meteor._LivedataConnection = function (url) {
|
||||
self.outstanding_methods = reload_data.outstanding_methods;
|
||||
// pending messages will be transmitted on initial stream 'reset'
|
||||
}
|
||||
Meteor._reload.on_migrate(reload_key, function () {
|
||||
Meteor._reload.on_migrate(reload_key, function (result) {
|
||||
var methods = _.map(self.outstanding_methods, function (m) {
|
||||
// filter out callback
|
||||
return {msg: m.msg};
|
||||
});
|
||||
|
||||
return { next_method_id: self.next_method_id,
|
||||
outstanding_methods: methods };
|
||||
result({ next_method_id: self.next_method_id,
|
||||
outstanding_methods: methods });
|
||||
});
|
||||
|
||||
// Setup stream
|
||||
|
||||
@@ -68,16 +68,18 @@
|
||||
}
|
||||
|
||||
|
||||
var save_callbacks = {};
|
||||
var providers = [];
|
||||
|
||||
////////// External API //////////
|
||||
|
||||
// Called by packages when they start up.
|
||||
// Registers a callback for when we want to save data.
|
||||
// Before a reload, callback is called, and should return
|
||||
// a JSONifyable object.
|
||||
// Before a reload, callback is called. It takes one argument, a
|
||||
// function. The package should wait until it is ready to migrate,
|
||||
// and then call the function. If it has migration data, it should
|
||||
// pass it to the function as a single JSON-compatible argument.
|
||||
Meteor._reload.on_migrate = function (name, callback) {
|
||||
save_callbacks[name] = callback;
|
||||
providers.push({name: name, callback: callback});
|
||||
};
|
||||
|
||||
// Called by packages when they start up.
|
||||
@@ -86,36 +88,55 @@
|
||||
return old_data[name];
|
||||
};
|
||||
|
||||
// Trigger a reload. Calls all the callbacks, saves all the values,
|
||||
// then blows up the world.
|
||||
// Trigger a reload. Starts a process that asynchronously calls all
|
||||
// the callbacks, saves all the values, and then terminates this VM
|
||||
// and starts a new one.
|
||||
var reloading = false;
|
||||
Meteor._reload.reload = function () {
|
||||
// Meteor._debug("Beginning hot reload.");
|
||||
if (reloading)
|
||||
return;
|
||||
reloading = true;
|
||||
|
||||
// ask everyone for stuff to save
|
||||
var new_data = {};
|
||||
_.each(save_callbacks, function (callback, name) {
|
||||
new_data[name] = callback();
|
||||
});
|
||||
// ask everyone for stuff to save, asynchronously
|
||||
var migration_data = {};
|
||||
var remaining = _.clone(providers);
|
||||
var requestNext = function () {
|
||||
var next = remaining.shift();
|
||||
if (!next)
|
||||
saveAndRestart();
|
||||
else
|
||||
next.callback(function (value) {
|
||||
if (value !== undefined)
|
||||
migration_data[next.name] = value;
|
||||
requestNext();
|
||||
});
|
||||
};
|
||||
|
||||
var new_json;
|
||||
try {
|
||||
new_json = JSON.stringify({
|
||||
time: (new Date()).getTime(), data: new_data, reload: true
|
||||
});
|
||||
} catch (err) {
|
||||
Meteor._debug("Asked to persist non-JSONable data. Ignoring.");
|
||||
new_json = '{}';
|
||||
}
|
||||
// then persist the migration data and restart
|
||||
var saveAndRestart = function () {
|
||||
var json;
|
||||
try {
|
||||
json = JSON.stringify({
|
||||
time: (new Date()).getTime(), data: migration_data, reload: true
|
||||
});
|
||||
} catch (err) {
|
||||
Meteor._debug("Asked to persist non-JSONable data. Ignoring.");
|
||||
json = '{}';
|
||||
}
|
||||
|
||||
// save it
|
||||
if (typeof sessionStorage !== "undefined") {
|
||||
sessionStorage.setItem(KEY_NAME, new_json);
|
||||
} else {
|
||||
Meteor._debug("Browser does not support sessionStorage. Not saving reload state.");
|
||||
}
|
||||
// save it
|
||||
if (typeof sessionStorage !== "undefined") {
|
||||
sessionStorage.setItem(KEY_NAME, json);
|
||||
} else {
|
||||
Meteor._debug("Browser does not support sessionStorage. Not saving reload state.");
|
||||
}
|
||||
|
||||
// blow up the world!
|
||||
window.location.reload();
|
||||
// Restart with the new code.
|
||||
window.location.reload();
|
||||
};
|
||||
|
||||
// kick off asynchronous process
|
||||
requestNext();
|
||||
};
|
||||
|
||||
})();
|
||||
|
||||
@@ -105,9 +105,9 @@ Session = _.extend({}, {
|
||||
|
||||
|
||||
if (Meteor._reload) {
|
||||
Meteor._reload.on_migrate('session', function () {
|
||||
Meteor._reload.on_migrate('session', function (result) {
|
||||
// XXX sanitize and make sure it's JSONible?
|
||||
return { keys: Session.keys };
|
||||
result({keys: Session.keys});
|
||||
});
|
||||
|
||||
(function () {
|
||||
|
||||
@@ -130,21 +130,21 @@ _.extend(Meteor._Stream.prototype, {
|
||||
// inspect the welcome data and decide if we have to reload
|
||||
try {
|
||||
var welcome_data = JSON.parse(welcome_message);
|
||||
if (welcome_data && welcome_data.server_id) {
|
||||
if (self.server_id && self.server_id !== welcome_data.server_id) {
|
||||
Meteor._reload.reload();
|
||||
// world's about to end, just leave the connection 'connecting'
|
||||
// until it does.
|
||||
return;
|
||||
}
|
||||
self.server_id = welcome_data.server_id;
|
||||
} else {
|
||||
Meteor._debug("DEBUG: invalid welcome packet", welcome_data);
|
||||
}
|
||||
} catch (err) {
|
||||
Meteor._debug("DEBUG: malformed welcome packet", welcome_message);
|
||||
}
|
||||
|
||||
if (welcome_data && welcome_data.server_id) {
|
||||
if (self.server_id && self.server_id !== welcome_data.server_id) {
|
||||
Meteor._reload.reload();
|
||||
// world's about to end, just leave the connection 'connecting'
|
||||
// until it does.
|
||||
return;
|
||||
}
|
||||
self.server_id = welcome_data.server_id;
|
||||
} else
|
||||
Meteor._debug("DEBUG: invalid welcome packet", welcome_data);
|
||||
|
||||
// update status
|
||||
self.current_status.status = "connected";
|
||||
self.current_status.connected = true;
|
||||
|
||||
Reference in New Issue
Block a user