Skip to content

Commit

Permalink
[Maps][Telemetry] Add cancel function to maps telemetry task (elastic…
Browse files Browse the repository at this point in the history
…#42769) (elastic#43533)

* Add cancelable promise wrapper to telemetry task. Add cancel function to task runner

* Add tests for task run and cancel operations
  • Loading branch information
Aaron Caldwell authored Aug 19, 2019
1 parent a332eaa commit 7a7d689
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 24 deletions.
57 changes: 45 additions & 12 deletions x-pack/legacy/plugins/maps/server/maps_telemetry/telemetry_task.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export function scheduleTask(server, taskManager) {
taskType: TELEMETRY_TASK_TYPE,
state: { stats: {}, runs: 0 },
});
}catch(e) {
} catch(e) {
server.log(['warning', 'maps'], `Error scheduling telemetry task, received ${e.message}`);
}
})();
Expand All @@ -52,32 +52,65 @@ export function telemetryTaskRunner(server) {
return ({ taskInstance }) => {
const { state } = taskInstance;
const prevState = state;
let mapsTelemetry = {};

const callCluster = server.plugins.elasticsearch.getCluster('admin')
.callWithInternalUser;

let mapsTelemetryTask;

return {
async run() {
async run({ taskCanceled = false } = {}) {
try {
mapsTelemetry = await getMapsTelemetry(server, callCluster);
mapsTelemetryTask = makeCancelable(
getMapsTelemetry(server, callCluster),
taskCanceled
);
} catch (err) {
server.log(['warning'], `Error loading maps telemetry: ${err}`);
} finally {
return {
state: {
runs: state.runs || 0 + 1,
stats: mapsTelemetry.attributes || prevState.stats || {},
},
runAt: getNextMidnight(),
};
return mapsTelemetryTask
.promise
.then((mapsTelemetry = {}) => {
return {
state: {
runs: state.runs || 0 + 1,
stats: mapsTelemetry.attributes || prevState.stats || {},
},
runAt: getNextMidnight(),
};
})
.catch(errMsg => server.log(['warning'],
`Error executing maps telemetry task: ${errMsg}`));
}
},
async cancel() {
if (mapsTelemetryTask) {
mapsTelemetryTask.cancel();
} else {
server.log(['warning'], `Can not cancel "mapsTelemetryTask", it has not been defined`);
}
}
};
};
}

export function getNextMidnight() {
function makeCancelable(promise, isCanceled) {
const logMsg = 'Maps telemetry task has been cancelled';
const wrappedPromise = new Promise((resolve, reject) => {
promise
.then(val => isCanceled ? reject(logMsg) : resolve(val))
.catch(err => isCanceled ? reject(logMsg) : reject(err.message));
});

return {
promise: wrappedPromise,
cancel() {
isCanceled = true;
},
};
}

function getNextMidnight() {
const nextMidnight = new Date();
nextMidnight.setHours(0, 0, 0, 0);
nextMidnight.setDate(nextMidnight.getDate() + 1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,39 +4,68 @@
* you may not use this file except in compliance with the Elastic License.
*/

import moment from 'moment';
import {
getMockKbnServer,
getMockTaskInstance,
} from '../test_utils';
import { telemetryTaskRunner } from './telemetry_task';
import * as mapsTelemetry from './maps_telemetry';
jest.mock('./maps_telemetry');

const expectedAttributes = {
expect: 'values',
toBe: 'populated'
};

const generateTelemetry = ({ includeAttributes = true } = {}) => {
mapsTelemetry.getMapsTelemetry = async () => ({ // eslint-disable-line
attributes: includeAttributes ? expectedAttributes : {}
});
};

describe('telemetryTaskRunner', () => {
let mockTaskInstance;
let mockKbnServer;
let taskRunner;

beforeEach(() => {
mockTaskInstance = getMockTaskInstance();
mockKbnServer = getMockKbnServer();
taskRunner = telemetryTaskRunner(mockKbnServer)({ taskInstance: mockTaskInstance });
});

test('Returns empty stats on error', async () => {
const getNextMidnight = () =>
moment()
.add(1, 'days')
.startOf('day')
.toDate();
test('returns empty stats as default', async () => {
generateTelemetry({ includeAttributes: false });

const getRunner = telemetryTaskRunner(mockKbnServer);
const runResult = await getRunner(
{ taskInstance: mockTaskInstance }
).run();
const runResult = await taskRunner.run();

expect(runResult).toMatchObject({
runAt: getNextMidnight(),
state: {
runs: 1,
stats: {},
},
});
});

// Return stats when run normally
test('returns stats normally', async () => {
generateTelemetry();

const runResult = await taskRunner.run();

expect(runResult).toMatchObject({
state: {
runs: 1,
stats: expectedAttributes,
},
});
});

test('cancels when cancel flag set to "true", returns undefined', async () => {
generateTelemetry();

const runResult = await taskRunner.run({ taskCanceled: true });

expect(runResult).toBe(undefined);
});
});

0 comments on commit 7a7d689

Please sign in to comment.