Skip to content

Commit

Permalink
Merge branch 'master' into lens/dnd_add_ghost_image_to_keyboard_navig…
Browse files Browse the repository at this point in the history
…ation
  • Loading branch information
kibanamachine authored Feb 9, 2021
2 parents a2f1c14 + 9314b8e commit 97c3393
Show file tree
Hide file tree
Showing 261 changed files with 7,076 additions and 3,435 deletions.
9 changes: 7 additions & 2 deletions docs/user/dashboard/vega-reference.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -251,17 +251,22 @@ experimental[] To enable *Maps*, the graph must specify `type=map` in the host c
"longitude": -74, // default 0
"zoom": 7, // default 2
// defaults to "default". Use false to disable base layer.
// Defaults to 'true', disables the base map layer.
"mapStyle": false,
// When 'mapStyle' is 'undefined' or 'true', sets the EMS-layer for the map.
// May either be: "road_map", "road_map_desaturated", "dark_map".
// If 'emsTileServiceId' is 'undefined', it falls back to the auto-switch-dark-light behavior.
"emsTileServiceId": "road_map",
// default 0
"minZoom": 5,
// defaults to the maximum for the given style,
// or 25 when base is disabled
"maxZoom": 13,
// defaults to true, shows +/- buttons to zoom in/out
// Defaults to 'true', shows +/- buttons to zoom in/out
"zoomControl": false,
// Defaults to 'false', disables mouse wheel zoom. If set to
Expand Down
22 changes: 9 additions & 13 deletions packages/kbn-std/src/promise.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,40 +12,36 @@ const delay = (ms: number, resolveValue?: any) =>
new Promise((resolve) => setTimeout(resolve, ms, resolveValue));

describe('withTimeout', () => {
it('resolves with a promise value if resolved in given timeout', async () => {
it('resolves with a promise value and "timedout: false" if resolved in given timeout', async () => {
await expect(
withTimeout({
promise: delay(10, 'value'),
timeout: 200,
errorMessage: 'error-message',
timeoutMs: 200,
})
).resolves.toBe('value');
).resolves.toStrictEqual({ value: 'value', timedout: false });
});

it('rejects with errorMessage if not resolved in given time', async () => {
it('resolves with "timedout: false" if not resolved in given time', async () => {
await expect(
withTimeout({
promise: delay(200, 'value'),
timeout: 10,
errorMessage: 'error-message',
timeoutMs: 10,
})
).rejects.toMatchInlineSnapshot(`[Error: error-message]`);
).resolves.toStrictEqual({ timedout: true });

await expect(
withTimeout({
promise: new Promise((i) => i),
timeout: 10,
errorMessage: 'error-message',
timeoutMs: 10,
})
).rejects.toMatchInlineSnapshot(`[Error: error-message]`);
).resolves.toStrictEqual({ timedout: true });
});

it('does not swallow promise error', async () => {
await expect(
withTimeout({
promise: Promise.reject(new Error('from-promise')),
timeout: 10,
errorMessage: 'error-message',
timeoutMs: 10,
})
).rejects.toMatchInlineSnapshot(`[Error: from-promise]`);
});
Expand Down
27 changes: 17 additions & 10 deletions packages/kbn-std/src/promise.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,26 @@
* Side Public License, v 1.
*/

export function withTimeout<T>({
export async function withTimeout<T>({
promise,
timeout,
errorMessage,
timeoutMs,
}: {
promise: Promise<T>;
timeout: number;
errorMessage: string;
}) {
return Promise.race([
promise,
new Promise((resolve, reject) => setTimeout(() => reject(new Error(errorMessage)), timeout)),
]) as Promise<T>;
timeoutMs: number;
}): Promise<{ timedout: true } | { timedout: false; value: T }> {
let timeout: NodeJS.Timeout | undefined;
try {
return (await Promise.race([
promise.then((v) => ({ value: v, timedout: false })),
new Promise((resolve) => {
timeout = setTimeout(() => resolve({ timedout: true }), timeoutMs);
}),
])) as Promise<{ timedout: true } | { timedout: false; value: T }>;
} finally {
if (timeout !== undefined) {
clearTimeout(timeout);
}
}
}

export function isPromise<T>(maybePromise: T | Promise<T>): maybePromise is Promise<T> {
Expand Down
26 changes: 20 additions & 6 deletions src/core/public/plugins/plugins_service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,11 +111,18 @@ export class PluginsService implements CoreService<PluginsServiceSetup, PluginsS
);
}

contract = await withTimeout({
const contractMaybe = await withTimeout({
promise: contractOrPromise,
timeout: 10 * Sec,
errorMessage: `Setup lifecycle of "${pluginName}" plugin wasn't completed in 10sec. Consider disabling the plugin and re-start.`,
timeoutMs: 10 * Sec,
});

if (contractMaybe.timedout) {
throw new Error(
`Setup lifecycle of "${pluginName}" plugin wasn't completed in 10sec. Consider disabling the plugin and re-start.`
);
} else {
contract = contractMaybe.value;
}
} else {
contract = contractOrPromise;
}
Expand Down Expand Up @@ -158,11 +165,18 @@ export class PluginsService implements CoreService<PluginsServiceSetup, PluginsS
);
}

contract = await withTimeout({
const contractMaybe = await withTimeout({
promise: contractOrPromise,
timeout: 10 * Sec,
errorMessage: `Start lifecycle of "${pluginName}" plugin wasn't completed in 10sec. Consider disabling the plugin and re-start.`,
timeoutMs: 10 * Sec,
});

if (contractMaybe.timedout) {
throw new Error(
`Start lifecycle of "${pluginName}" plugin wasn't completed in 10sec. Consider disabling the plugin and re-start.`
);
} else {
contract = contractMaybe.value;
}
} else {
contract = contractOrPromise;
}
Expand Down
42 changes: 42 additions & 0 deletions src/core/server/plugins/plugins_system.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -621,3 +621,45 @@ describe('asynchronous plugins', () => {
`);
});
});

describe('stop', () => {
beforeAll(() => {
jest.useFakeTimers();
});

afterAll(() => {
jest.useRealTimers();
});

it('waits for 30 sec to finish "stop" and move on to the next plugin.', async () => {
const [plugin1, plugin2] = [createPlugin('timeout-stop-1'), createPlugin('timeout-stop-2')].map(
(plugin, index) => {
jest.spyOn(plugin, 'setup').mockResolvedValue(`setup-as-${index}`);
jest.spyOn(plugin, 'start').mockResolvedValue(`started-as-${index}`);
pluginsSystem.addPlugin(plugin);
return plugin;
}
);

const stopSpy1 = jest
.spyOn(plugin1, 'stop')
.mockImplementationOnce(() => new Promise((resolve) => resolve));
const stopSpy2 = jest.spyOn(plugin2, 'stop').mockImplementationOnce(() => Promise.resolve());

mockCreatePluginSetupContext.mockImplementation(() => ({}));

await pluginsSystem.setupPlugins(setupDeps);
const stopPromise = pluginsSystem.stopPlugins();

jest.runAllTimers();
await stopPromise;
expect(stopSpy1).toHaveBeenCalledTimes(1);
expect(stopSpy2).toHaveBeenCalledTimes(1);

expect(loggingSystemMock.collect(logger).warn.flat()).toEqual(
expect.arrayContaining([
`"timeout-stop-1" plugin didn't stop in 30sec., move on to the next.`,
])
);
});
});
36 changes: 29 additions & 7 deletions src/core/server/plugins/plugins_system.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,11 +105,18 @@ export class PluginsSystem {
`Plugin ${pluginName} is using asynchronous setup lifecycle. Asynchronous plugins support will be removed in a later version.`
);
}
contract = await withTimeout({
const contractMaybe = await withTimeout<any>({
promise: contractOrPromise,
timeout: 10 * Sec,
errorMessage: `Setup lifecycle of "${pluginName}" plugin wasn't completed in 10sec. Consider disabling the plugin and re-start.`,
timeoutMs: 10 * Sec,
});

if (contractMaybe.timedout) {
throw new Error(
`Setup lifecycle of "${pluginName}" plugin wasn't completed in 10sec. Consider disabling the plugin and re-start.`
);
} else {
contract = contractMaybe.value;
}
} else {
contract = contractOrPromise;
}
Expand Down Expand Up @@ -154,11 +161,18 @@ export class PluginsSystem {
`Plugin ${pluginName} is using asynchronous start lifecycle. Asynchronous plugins support will be removed in a later version.`
);
}
contract = await withTimeout({
const contractMaybe = await withTimeout({
promise: contractOrPromise,
timeout: 10 * Sec,
errorMessage: `Start lifecycle of "${pluginName}" plugin wasn't completed in 10sec. Consider disabling the plugin and re-start.`,
timeoutMs: 10 * Sec,
});

if (contractMaybe.timedout) {
throw new Error(
`Start lifecycle of "${pluginName}" plugin wasn't completed in 10sec. Consider disabling the plugin and re-start.`
);
} else {
contract = contractMaybe.value;
}
} else {
contract = contractOrPromise;
}
Expand All @@ -181,7 +195,15 @@ export class PluginsSystem {
const pluginName = this.satupPlugins.pop()!;

this.log.debug(`Stopping plugin "${pluginName}"...`);
await this.plugins.get(pluginName)!.stop();

const resultMaybe = await withTimeout({
promise: this.plugins.get(pluginName)!.stop(),
timeoutMs: 30 * Sec,
});

if (resultMaybe?.timedout) {
this.log.warn(`"${pluginName}" plugin didn't stop in 30sec., move on to the next.`);
}
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/plugins/data/public/search/session/sessions_client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,9 @@ export class SessionsClient {
});
}

public extend(sessionId: string, keepAlive: string): Promise<SavedObjectsFindResponse> {
public extend(sessionId: string, expires: string): Promise<SavedObjectsFindResponse> {
return this.http!.post(`/internal/session/${encodeURIComponent(sessionId)}/_extend`, {
body: JSON.stringify({ keepAlive }),
body: JSON.stringify({ expires }),
});
}

Expand Down
Loading

0 comments on commit 97c3393

Please sign in to comment.