|
|
@@ -13,25 +13,26 @@ The {@link module:watchdog/watchdog~Watchdog} utility allows you to do exactly t
|
|
|
|
|
|
It should be noticed that the most "dangerous" places in the API - like `editor.model.change()`, `editor.editing.view.change()`, emitters - are covered with checks and `try-catch` blocks that allow detecting unknown errors and restart editor when they occur.
|
|
|
|
|
|
-Currently there are two available watchdogs, which can be used depending on your needs:
|
|
|
-* [editor watchdog](#editor-watchdog) - that fills the most basic scenario when only one editor is created,
|
|
|
-* [context watchdog](#context-watchdog) - that keeps an advanced structure of connected editors via te context feature running
|
|
|
+There are two available types of watchdogs:
|
|
|
|
|
|
-## Usage
|
|
|
-
|
|
|
-### Editor watchdog
|
|
|
+* [editor watchdog](#editor-watchdog) - to be used with a single editor instance,
|
|
|
+* [context watchdog](#context-watchdog) - to be used when your application uses `Context`.
|
|
|
|
|
|
<info-box>
|
|
|
- Note: The editor watchdog can be used only with an {@link builds/guides/integration/advanced-setup#scenario-2-building-from-source editor built from source}.
|
|
|
+ Note: a watchdog can be used only with an {@link builds/guides/integration/advanced-setup#scenario-2-building-from-source editor built from source}.
|
|
|
</info-box>
|
|
|
|
|
|
+## Usage
|
|
|
+
|
|
|
+### Editor watchdog
|
|
|
+
|
|
|
Install the [`@ckeditor/ckeditor5-watchdog`](https://www.npmjs.com/package/@ckeditor/ckeditor5-watchdog) package:
|
|
|
|
|
|
```bash
|
|
|
npm install --save @ckeditor/ckeditor5-watchdog
|
|
|
```
|
|
|
|
|
|
-And then change your `ClassicEditor.create()` call to `watchdog.create()` as follows:
|
|
|
+Then, change your `ClassicEditor.create()` call to `watchdog.create()` as follows:
|
|
|
|
|
|
```js
|
|
|
import ClassicEditor from '@ckeditor/ckeditor5-editor-classic/src/classiceditor';
|
|
|
@@ -57,17 +58,18 @@ In other words, your goal is to create a watchdog instance and make the watchdog
|
|
|
<info-box>
|
|
|
A new editor instance is created every time the watchdog detects a crash. Thus, the editor instance should not be kept in your application's state. Use the {@link module:watchdog/editorwatchdog~EditorWatchdog#editor `EditorWatchdog#editor`} property instead.
|
|
|
|
|
|
- It also means that any code that should be executed for any new editor instance should be either loaded as an editor plugin or executed in the callbacks defined by {@link module:watchdog/editorwatchdog~EditorWatchdog#setCreator `EditorWatchdog#setCreator()`} and {@link module:watchdog/editorwatchdog~EditorWatchdog#setDestructor `EditorWatchdog#setDestructor()`}. Read more about controlling the editor creation and destruction in the next section.
|
|
|
+ It also means that any code that should be executed for any new editor instance should be either loaded as an editor plugin or executed in the callbacks defined using {@link module:watchdog/editorwatchdog~EditorWatchdog#setCreator `EditorWatchdog#setCreator()`} and {@link module:watchdog/editorwatchdog~EditorWatchdog#setDestructor `EditorWatchdog#setDestructor()`}. Read more about controlling the editor creation and destruction in the next section.
|
|
|
</info-box>
|
|
|
|
|
|
#### Controlling editor creation and destruction
|
|
|
|
|
|
-For more control over the creation and destruction of editor instances, you can use the {@link module:watchdog/editorwatchdog~EditorWatchdog#setCreator `EditorWatchdog#setCreator()`} and, if needed, the {@link module:watchdog/editorwatchdog~EditorWatchdog#setDestructor `EditorWatchdog#setDestructor()`} methods:
|
|
|
+For more control over the creation and destruction of editor instances, you can use {@link module:watchdog/editorwatchdog~EditorWatchdog#setCreator `EditorWatchdog#setCreator()`} and, if needed, the {@link module:watchdog/editorwatchdog~EditorWatchdog#setDestructor `EditorWatchdog#setDestructor()`}:
|
|
|
|
|
|
```js
|
|
|
-// Instantiate the watchdog manually (do not use the for() helper).
|
|
|
+// Create editor watchdog.
|
|
|
const watchdog = new EditorWatchdog();
|
|
|
|
|
|
+// Define a callback that will create an editor instance and return it.
|
|
|
watchdog.setCreator( ( elementOrData, editorConfig ) => {
|
|
|
return ClassicEditor
|
|
|
.create( elementOrData, editorConfig )
|
|
|
@@ -76,21 +78,23 @@ watchdog.setCreator( ( elementOrData, editorConfig ) => {
|
|
|
} );
|
|
|
} );
|
|
|
|
|
|
+// Do something before the editor is destroyed. Return a promise.
|
|
|
watchdog.setDestructor( editor => {
|
|
|
- // Do something before the editor is destroyed.
|
|
|
+ // ...
|
|
|
|
|
|
return editor
|
|
|
.destroy()
|
|
|
.then( () => {
|
|
|
// Do something after the editor is destroyed.
|
|
|
} );
|
|
|
- } );
|
|
|
+} );
|
|
|
|
|
|
+// Create editor instance and start watching it.
|
|
|
watchdog.create( elementOrData, editorConfig );
|
|
|
```
|
|
|
|
|
|
<info-box>
|
|
|
- The default (not overridden) editor destructor is the `editor => editor.destroy()` function.
|
|
|
+ The default (not overridden ny `setDestructor()`) editor destructor simply executes `Editor#destroy()`.
|
|
|
</info-box>
|
|
|
|
|
|
#### Editor watchdog API
|
|
|
@@ -109,6 +113,7 @@ watchdog.editor;
|
|
|
|
|
|
// The current state of the editor.
|
|
|
// The editor might be in one of the following states:
|
|
|
+//
|
|
|
// * `initializing` - before the first initialization, and after crashes, before the editor is ready,
|
|
|
// * `ready` - a state when a user can interact with the editor,
|
|
|
// * `crashed` - a state when an error occurs - it quickly changes to `initializing` or `crashedPermanently` depending on how many and how frequency errors have been caught recently,
|
|
|
@@ -138,10 +143,6 @@ watchdog.crashes.forEach( crashInfo => console.log( crashInfo ) );
|
|
|
|
|
|
### Context watchdog
|
|
|
|
|
|
-<info-box>
|
|
|
- Note: the context watchdog can be used only with an {@link builds/guides/integration/advanced-setup#scenario-2-building-from-source editor built from source}.
|
|
|
-</info-box>
|
|
|
-
|
|
|
Install the [`@ckeditor/ckeditor5-watchdog`](https://www.npmjs.com/package/@ckeditor/ckeditor5-watchdog) package:
|
|
|
|
|
|
```bash
|
|
|
@@ -160,17 +161,21 @@ import Bold from '@ckeditor/ckeditor5-basic-styles/src/bold';
|
|
|
import Italic from '@ckeditor/ckeditor5-basic-styles/src/italic';
|
|
|
import Context from '@ckeditor/ckeditor5-core/src/context';
|
|
|
|
|
|
-// Create a watchdog for the context and pass the `Context` class with optional watchdog configuration:
|
|
|
+// Create a context watchdog and pass the `Context` class with optional watchdog configuration:
|
|
|
const watchdog = new ContextWatchdog( Context, {
|
|
|
crashNumberLimit: 10
|
|
|
} );
|
|
|
|
|
|
-// Initialize it with the context configuration:
|
|
|
+// Initialize the watchdog with context configuration:
|
|
|
await watchdog.create( {
|
|
|
- plugins: []
|
|
|
-} )
|
|
|
+ plugins: [
|
|
|
+ // ...
|
|
|
+ ],
|
|
|
+ // ...
|
|
|
+} );
|
|
|
|
|
|
-// Add editor instances:
|
|
|
+// Add editor instances.
|
|
|
+// You mat also use multiple `ContextWatchdog#add()` calls, each adding a single editor.
|
|
|
await watchdog.add( [ {
|
|
|
id: 'editor1',
|
|
|
type: 'editor',
|
|
|
@@ -190,26 +195,44 @@ await watchdog.add( [ {
|
|
|
},
|
|
|
creator: ( element, config ) => ClassicEditor.create( element, config )
|
|
|
} ] );
|
|
|
-```
|
|
|
|
|
|
-<info-box>
|
|
|
- The Watchdog will keep the context and item instances running
|
|
|
- that are added via the {@link module:watchdog/contextwatchdog~ContextWatchdog#add `ContextWatchdog#add` method}. This method can be called multiple times during the `ContextWatchdog` lifetime.
|
|
|
+// Or:
|
|
|
+await watchdog.add( {
|
|
|
+ id: 'editor1',
|
|
|
+ type: 'editor',
|
|
|
+ sourceElementOrData: document.querySelector( '#editor' ),
|
|
|
+ config: {
|
|
|
+ plugins: [ Essentials, Paragraph, Bold, Italic ],
|
|
|
+ toolbar: [ 'bold', 'italic', 'alignment' ]
|
|
|
+ },
|
|
|
+ creator: ( element, config ) => ClassicEditor.create( element, config )
|
|
|
+} );
|
|
|
|
|
|
- To destroy one of the item instances use the {@link module:watchdog/contextwatchdog~ContextWatchdog#remove `ContextWatchdog#remove` method}. This method can be called multiple times during the `ContextWatchdog` lifetime as well.
|
|
|
-</info-box>
|
|
|
+await watchdog.add( {
|
|
|
+ id: 'editor2',
|
|
|
+ type: 'editor',
|
|
|
+ sourceElementOrData: document.querySelector( '#editor' ),
|
|
|
+ config: {
|
|
|
+ plugins: [ Essentials, Paragraph, Bold, Italic ],
|
|
|
+ toolbar: [ 'bold', 'italic', 'alignment' ]
|
|
|
+ },
|
|
|
+ creator: ( element, config ) => ClassicEditor.create( element, config )
|
|
|
+} );
|
|
|
+```
|
|
|
+
|
|
|
+To destroy one of the item instances use {@link module:watchdog/contextwatchdog~ContextWatchdog#remove `ContextWatchdog#remove`}:
|
|
|
|
|
|
```js
|
|
|
await watchdog.remove( [ 'editor1', 'editor2' ] );
|
|
|
|
|
|
-// Or
|
|
|
+// Or:
|
|
|
await watchdog.remove( 'editor1' );
|
|
|
await watchdog.remove( 'editor2' );
|
|
|
```
|
|
|
|
|
|
<info-box>
|
|
|
Examples presents the "synchronous way" of the integration with the context watchdog feature, however it's not needed to wait for the promises returned by the `create()`, `add()` and `remove()` methods. There might be a need
|
|
|
- to create and destroy items dynamically with shared context and that's can be easily achieved as all promises operating on the internal API will be chained.
|
|
|
+ to create and destroy items dynamically with shared context and that can be easily achieved as all promises operating on the internal API will be chained.
|
|
|
</info-box>
|
|
|
|
|
|
#### Context watchdog API
|
|
|
@@ -217,19 +240,19 @@ await watchdog.remove( 'editor2' );
|
|
|
The context watchdog feature provides the following API:
|
|
|
|
|
|
```js
|
|
|
-// Creating watchdog that will use the `Context` class and given configuration.
|
|
|
+// Creating watchdog that will use the `Context` class and watchdog configuration.
|
|
|
const watchdog = new ContextWatchdog( Context, watchdogConfig );
|
|
|
|
|
|
-// Setting a custom creator.
|
|
|
+// Setting a custom creator for the context.
|
|
|
watchdog.setCreator( async config => {
|
|
|
- const context = await Context.create( config ) );
|
|
|
+ const context = await Context.create( config );
|
|
|
|
|
|
// Do something when the context is initialized.
|
|
|
|
|
|
return context;
|
|
|
} );
|
|
|
|
|
|
-// Setting a custom destructor.
|
|
|
+// Setting a custom destructor for the context.
|
|
|
watchdog.setDestructor( async context => {
|
|
|
// Do something before destroy.
|
|
|
|
|
|
@@ -243,42 +266,56 @@ await watchdog.create( contextConfig );
|
|
|
await watchdog.add( {
|
|
|
id: 'editor1',
|
|
|
type: 'editor',
|
|
|
- sourceElementOrData: editorSourceElementOrEditorData
|
|
|
+ sourceElementOrData: domElementOrEditorData
|
|
|
config: editorConfig,
|
|
|
creator: createEditor,
|
|
|
destructor: destroyEditor,
|
|
|
} );
|
|
|
|
|
|
-// Removing and destroy given item.
|
|
|
-await watchdog.remove( [ 'editor1' ] );
|
|
|
+await watchdog.add( [
|
|
|
+ {
|
|
|
+ id: 'editor1',
|
|
|
+ type: 'editor',
|
|
|
+ sourceElementOrData: domElementOrEditorData
|
|
|
+ config: editorConfig,
|
|
|
+ creator: createEditor,
|
|
|
+ destructor: destroyEditor,
|
|
|
+ },
|
|
|
+ // ...
|
|
|
+] );
|
|
|
+
|
|
|
+// Remove and destroy given item (or items).
|
|
|
+await watchdog.remove( 'editor1' );
|
|
|
+
|
|
|
+await watchdog.remove( [ 'editor1', 'editor2', ... ] );
|
|
|
|
|
|
// Getting given item instance.
|
|
|
-const editor1 = watchdog.get( 'editor1' );
|
|
|
+const editor1 = watchdog.getItem( 'editor1' );
|
|
|
|
|
|
// Getting given item state.
|
|
|
-const editor1State = watchdog.getState( 'editor1' );
|
|
|
+const editor1State = watchdog.getItemState( 'editor1' );
|
|
|
|
|
|
// Getting the context state.
|
|
|
const contextState = watchdog.state;
|
|
|
|
|
|
-// The `error` event is fired when the context watchdog catches the context-related error.
|
|
|
-// Note that the item errors are not re-fired in the `ContextWatchdog#error`.
|
|
|
+// The `error` event is fired when the context watchdog catches a context-related error.
|
|
|
+// Note that errors fired by items are not delegated to `ContextWatchdog#event:error`.
|
|
|
+// See also `ContextWatchdog#event:itemError`.
|
|
|
watchdog.on( 'error', ( _, { error } ) => {
|
|
|
- console.log( 'The context crashed.' );
|
|
|
-} );
|
|
|
|
|
|
-// The `restarted` event is fired when the context is set back to the `ready` state (after it was in `error` state).
|
|
|
+// The `restart` event is fired when the context is set back to the `ready` state (after it was in `crashed` state).
|
|
|
// Similarly, this event is not thrown for internal item restarts.
|
|
|
watchdog.on( 'restart', () => {
|
|
|
console.log( 'The context has been restarted.' );
|
|
|
} );
|
|
|
|
|
|
-// The `itemError` event is fired when an error occurred in one of the added items
|
|
|
+
|
|
|
+// The `itemError` event is fired when an error occurred in one of the added items.
|
|
|
watchdog.on( 'itemError', ( _, { error, itemId } ) => {
|
|
|
console.log( `An error occurred in an item with the '${ itemId }' id.` );
|
|
|
} );
|
|
|
|
|
|
-// The `itemRestarted` event is fired when the item is set back to the `ready` state (after it was in `error` state).
|
|
|
+// The `itemRestart` event is fired when an item is set back to the `ready` state (after it was in `crashed` state).
|
|
|
watchdog.on( 'itemRestart', ( _, { itemId } ) => {
|
|
|
console.log( 'An item with with the '${ itemId }' id has been restarted.' );
|
|
|
} );
|
|
|
@@ -286,10 +323,10 @@ watchdog.on( 'itemRestart', ( _, { itemId } ) => {
|
|
|
|
|
|
## Configuration
|
|
|
|
|
|
-Both, {@link module:watchdog/editorwatchdog~EditorWatchdog#constructor `EditorWatchdog`} and {@link module:watchdog/contextwatchdog~ContextWatchdog#constructor `ContextWatchdog`} constructors accept a {{@link module:watchdog/watchdog~WatchdogConfig configuration object} as the second argument with the following optional properties:
|
|
|
+Both {@link module:watchdog/editorwatchdog~EditorWatchdog#constructor `EditorWatchdog`} and {@link module:watchdog/contextwatchdog~ContextWatchdog#constructor `ContextWatchdog`} constructors accept a {{@link module:watchdog/watchdog~WatchdogConfig configuration object} as the second argument with the following optional properties:
|
|
|
|
|
|
-* `crashNumberLimit` - A threshold specifying the number of editor errors (defaults to `3`). After this limit is reached and the time between last errors is shorter than `minimumNonErrorTimePeriod` the watchdog changes its state to `crashedPermanently` and it stops restarting the editor. This prevents an infinite restart loop.
|
|
|
-* `minimumNonErrorTimePeriod` - An average amount of milliseconds between last editor errors (defaults to 5000). When the period of time between errors is lower than that and the `crashNumberLimit` is also reached the watchdog changes its state to `crashedPermanently` and it stops restarting the editor. This prevents an infinite restart loop.
|
|
|
+* `crashNumberLimit` - A threshold specifying the number of errors (defaults to `3`). After this limit is reached and the time between last errors is shorter than `minimumNonErrorTimePeriod` the watchdog changes its state to `crashedPermanently` and it stops restarting the editor. This prevents an infinite restart loop.
|
|
|
+* `minimumNonErrorTimePeriod` - An average amount of milliseconds between last editor errors (defaults to 5000). When the period of time between errors is lower than that and the `crashNumberLimit` is also reachedm the watchdog changes its state to `crashedPermanently` and it stops restarting the editor. This prevents an infinite restart loop.
|
|
|
* `saveInterval` - A minimum number of milliseconds between saving editor data internally (defaults to 5000). Note that for large documents this might have an impact on the editor performance.
|
|
|
|
|
|
```js
|
|
|
@@ -297,13 +334,13 @@ const editorWatchdog = new EditorWatchdog( ClassicEditor, {
|
|
|
minimumNonErrorTimePeriod: 2000,
|
|
|
crashNumberLimit: 4,
|
|
|
saveInterval: 1000
|
|
|
-} )
|
|
|
+} );
|
|
|
```
|
|
|
|
|
|
<info-box>
|
|
|
- Note that the context watchdog passes its configuration to the added editors.
|
|
|
+ Note that the context watchdog passes its configuration to editor watchdogs that it creates for added editors.
|
|
|
</info-box>
|
|
|
|
|
|
## Limitations
|
|
|
|
|
|
-The watchdog does not handle errors thrown during the editor or context initialization (by e.g. `Editor.create()`) and editor destruction (e.g. `Editor#destroy()`). Errors thrown at these stages mean that there is a problem in the code integrating the editor with your application and such a problem cannot be fixed by restarting the editor.
|
|
|
+The watchdogs do not handle errors thrown during the editor or context initialization (e.g. in `Editor.create()`) and editor destruction (e.g. in `Editor#destroy()`). Errors thrown at these stages mean that there is a problem in the code integrating the editor with your application and such problem cannot be fixed by restarting the editor.
|