mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-02-24 23:48:13 -05:00
Improved "Server unreachable" error handling in editor
refs https://github.com/TryGhost/Team/issues/788 - automatically retry any failed save attempts every 5 seconds for up to 30 seconds - only show error bar after when we completely give up - clear error bar if a later save is successful - update error message to specify there's a connection problem and to retry with Cmd+S - notify Sentry of a successful save after an initial failure including the number of attempts that were made and the total time for save to succeed in seconds
This commit is contained in:
parent
81bfc3c6f6
commit
ac094821c8
1 changed files with 45 additions and 3 deletions
|
@ -7,12 +7,13 @@ import moment from 'moment';
|
||||||
import {action, computed} from '@ember/object';
|
import {action, computed} from '@ember/object';
|
||||||
import {alias, mapBy} from '@ember/object/computed';
|
import {alias, mapBy} from '@ember/object/computed';
|
||||||
import {capitalize} from '@ember/string';
|
import {capitalize} from '@ember/string';
|
||||||
|
import {captureException, captureMessage} from '@sentry/browser';
|
||||||
import {inject as controller} from '@ember/controller';
|
import {inject as controller} from '@ember/controller';
|
||||||
import {get} from '@ember/object';
|
import {get} from '@ember/object';
|
||||||
import {htmlSafe} from '@ember/template';
|
import {htmlSafe} from '@ember/template';
|
||||||
import {isBlank} from '@ember/utils';
|
import {isBlank} from '@ember/utils';
|
||||||
import {isArray as isEmberArray} from '@ember/array';
|
import {isArray as isEmberArray} from '@ember/array';
|
||||||
import {isHostLimitError} from 'ghost-admin/services/ajax';
|
import {isHostLimitError, isServerUnreachableError} from 'ghost-admin/services/ajax';
|
||||||
import {isInvalidError} from 'ember-ajax/errors';
|
import {isInvalidError} from 'ember-ajax/errors';
|
||||||
import {isVersionMismatchError} from 'ghost-admin/services/ajax';
|
import {isVersionMismatchError} from 'ghost-admin/services/ajax';
|
||||||
import {inject as service} from '@ember/service';
|
import {inject as service} from '@ember/service';
|
||||||
|
@ -85,6 +86,8 @@ const messageMap = {
|
||||||
|
|
||||||
export default Controller.extend({
|
export default Controller.extend({
|
||||||
application: controller(),
|
application: controller(),
|
||||||
|
|
||||||
|
config: service(),
|
||||||
feature: service(),
|
feature: service(),
|
||||||
membersCountCache: service(),
|
membersCountCache: service(),
|
||||||
notifications: service(),
|
notifications: service(),
|
||||||
|
@ -595,7 +598,44 @@ export default Controller.extend({
|
||||||
_savePostTask: task(function* (options) {
|
_savePostTask: task(function* (options) {
|
||||||
let {post} = this;
|
let {post} = this;
|
||||||
|
|
||||||
|
// retry save every 5 seconds for a total of 30secs
|
||||||
|
// only retry if we get a ServerUnreachable error (code 0) from the browser
|
||||||
|
let attempts = 0;
|
||||||
|
let maxAttempts = 2;
|
||||||
|
let startTime = moment();
|
||||||
|
let success = false;
|
||||||
|
while (attempts < maxAttempts && !success) {
|
||||||
|
try {
|
||||||
yield post.save(options);
|
yield post.save(options);
|
||||||
|
success = true;
|
||||||
|
this.notifications.closeAlerts('post.save');
|
||||||
|
|
||||||
|
if (attempts !== 0 && this.config.get('sentry_dsn')) {
|
||||||
|
let totalSeconds = moment().diff(startTime, 'seconds');
|
||||||
|
captureMessage('Saving post required multiple attempts', {attempts, totalSeconds});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log('caught error', {error});
|
||||||
|
attempts += 1;
|
||||||
|
|
||||||
|
if (isServerUnreachableError(error) && attempts < maxAttempts) {
|
||||||
|
yield timeout(5 * 1000);
|
||||||
|
} else if (isServerUnreachableError(error)) {
|
||||||
|
const status = this.post.status;
|
||||||
|
this._showErrorAlert(status, status, error);
|
||||||
|
if (this.config.get('sentry_dsn')) {
|
||||||
|
captureException(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// simulate a validation error so we don't end up on a 500 screen
|
||||||
|
console.log('throwing undefined');
|
||||||
|
throw undefined;
|
||||||
|
} else {
|
||||||
|
console.log('throwing error', isServerUnreachableError(error), error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// remove any unsaved tags
|
// remove any unsaved tags
|
||||||
// NOTE: `updateTags` changes `hasDirtyAttributes => true`.
|
// NOTE: `updateTags` changes `hasDirtyAttributes => true`.
|
||||||
|
@ -964,7 +1004,9 @@ export default Controller.extend({
|
||||||
return toString.call(str) === '[object String]';
|
return toString.call(str) === '[object String]';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (error && isString(error)) {
|
if (isServerUnreachableError(error)) {
|
||||||
|
errorMessage = 'Unable to connect, please check your connection and press Ctrl/Cmd+S to retry.';
|
||||||
|
} else if (error && isString(error)) {
|
||||||
errorMessage = error;
|
errorMessage = error;
|
||||||
} else if (error && isEmberArray(error)) {
|
} else if (error && isEmberArray(error)) {
|
||||||
// This is here because validation errors are returned as an array
|
// This is here because validation errors are returned as an array
|
||||||
|
|
Loading…
Add table
Reference in a new issue