Skip to content

Commit 64af6f6

Browse files
committed
[Task manager] Adds ensureScheduling api to allow safer rescheduling of existing tasks (elastic#50232)
Adds an ensureScheduling api to Task Manager which allow safer rescheduling of existing tasks by handling the case where a Task with a known ID is scheduled and clashes with an existing schedule of that same task.
1 parent fc94297 commit 64af6f6

File tree

14 files changed

+190
-15
lines changed

14 files changed

+190
-15
lines changed

x-pack/legacy/plugins/lens/server/usage/task.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ function scheduleTasks(server: Server) {
8686
// function block.
8787
(async () => {
8888
try {
89-
await taskManager.schedule({
89+
await taskManager.ensureScheduled({
9090
id: TASK_ID,
9191
taskType: TELEMETRY_TASK_TYPE,
9292
state: { byDate: {}, suggestionsByDate: {}, saved: {}, runs: 0 },

x-pack/legacy/plugins/maps/server/maps_telemetry/telemetry_task.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export function scheduleTask(server) {
2929
// function block.
3030
(async () => {
3131
try {
32-
await taskManager.schedule({
32+
await taskManager.ensureScheduled({
3333
id: TASK_ID,
3434
taskType: TELEMETRY_TASK_TYPE,
3535
state: { stats: {}, runs: 0 },

x-pack/legacy/plugins/oss_telemetry/index.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ export interface HapiServer {
4646
};
4747
task_manager: {
4848
registerTaskDefinitions: (opts: any) => void;
49-
schedule: (opts: any) => Promise<void>;
49+
ensureScheduled: (opts: any) => Promise<void>;
5050
fetch: (
5151
opts: any
5252
) => Promise<{

x-pack/legacy/plugins/oss_telemetry/server/lib/tasks/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ export function scheduleTasks(server: HapiServer) {
4242
// function block.
4343
(async () => {
4444
try {
45-
await taskManager.schedule({
45+
await taskManager.ensureScheduled({
4646
id: `${PLUGIN_ID}-${VIS_TELEMETRY_TASK}`,
4747
taskType: VIS_TELEMETRY_TASK,
4848
state: { stats: {}, runs: 0 },

x-pack/legacy/plugins/oss_telemetry/test_utils/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ export const getMockKbnServer = (
5050
xpack_main: {},
5151
task_manager: {
5252
registerTaskDefinitions: (opts: any) => undefined,
53-
schedule: (opts: any) => Promise.resolve(),
53+
ensureScheduled: (opts: any) => Promise.resolve(),
5454
fetch: mockTaskFetch,
5555
},
5656
},

x-pack/legacy/plugins/task_manager/README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,9 @@ The data stored for a task instance looks something like this:
222222

223223
The task manager mixin exposes a taskManager object on the Kibana server which plugins can use to manage scheduled tasks. Each method takes an optional `scope` argument and ensures that only tasks with the specified scope(s) will be affected.
224224

225+
### schedule
226+
Using `schedule` you can instruct TaskManger to schedule an instance of a TaskType at some point in the future.
227+
225228
```js
226229
const taskManager = server.plugins.task_manager;
227230
// Schedules a task. All properties are as documented in the previous
@@ -256,6 +259,14 @@ const results = await manager.find({ scope: 'my-fanci-app', searchAfter: ['ids']
256259
}
257260
```
258261

262+
### ensureScheduling
263+
When using the `schedule` api to schedule a Task you can provide a hard coded `id` on the Task. This tells TaskManager to use this `id` to identify the Task Instance rather than generate an `id` on its own.
264+
The danger is that in such a situation, a Task with that same `id` might already have been scheduled at some earlier point, and this would result in an error. In some cases, this is the expected behavior, but often you only care about ensuring the task has been _scheduled_ and don't need it to be scheduled a fresh.
265+
266+
To achieve this you should use the `ensureScheduling` api which has the exact same behavior as `schedule`, except it allows the scheduling of a Task with an `id` that's already in assigned to another Task and it will assume that the existing Task is the one you wished to `schedule`, treating this as a successful operation.
267+
268+
### more options
269+
259270
More custom access to the tasks can be done directly via Elasticsearch, though that won't be officially supported, as we can change the document structure at any time.
260271

261272
## Middleware

x-pack/legacy/plugins/task_manager/plugin.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ describe('Task Manager Plugin', () => {
4242
expect(setupResult).toMatchInlineSnapshot(`
4343
Object {
4444
"addMiddleware": [Function],
45+
"ensureScheduled": [Function],
4546
"fetch": [Function],
4647
"registerTaskDefinitions": [Function],
4748
"remove": [Function],

x-pack/legacy/plugins/task_manager/plugin.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export interface PluginSetupContract {
1111
fetch: TaskManager['fetch'];
1212
remove: TaskManager['remove'];
1313
schedule: TaskManager['schedule'];
14+
ensureScheduled: TaskManager['ensureScheduled'];
1415
addMiddleware: TaskManager['addMiddleware'];
1516
registerTaskDefinitions: TaskManager['registerTaskDefinitions'];
1617
}
@@ -59,6 +60,7 @@ export class Plugin {
5960
fetch: (...args) => taskManager.fetch(...args),
6061
remove: (...args) => taskManager.remove(...args),
6162
schedule: (...args) => taskManager.schedule(...args),
63+
ensureScheduled: (...args) => taskManager.ensureScheduled(...args),
6264
addMiddleware: (...args) => taskManager.addMiddleware(...args),
6365
registerTaskDefinitions: (...args) => taskManager.registerTaskDefinitions(...args),
6466
};

x-pack/legacy/plugins/task_manager/task.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,20 @@ import Joi from 'joi';
1010
* Type definitions and validations for tasks.
1111
*/
1212

13+
/**
14+
* Require
15+
* @desc Create a Subtype of type T `T` such that the property under key `P` becomes required
16+
* @example
17+
* type TaskInstance = {
18+
* id?: string;
19+
* name: string;
20+
* };
21+
*
22+
* // This type is now defined as { id: string; name: string; }
23+
* type TaskInstanceWithId = Require<TaskInstance, 'id'>;
24+
*/
25+
type Require<T extends object, P extends keyof T> = Omit<T, P> & Required<Pick<T, P>>;
26+
1327
/**
1428
* A loosely typed definition of the elasticjs wrapper. It's beyond the scope
1529
* of this work to try to make a comprehensive type definition of this.
@@ -216,6 +230,11 @@ export interface TaskInstance {
216230
ownerId?: string | null;
217231
}
218232

233+
/**
234+
* A task instance that has an id.
235+
*/
236+
export type TaskInstanceWithId = Require<TaskInstance, 'id'>;
237+
219238
/**
220239
* A task instance that has an id and is ready for storage.
221240
*/

x-pack/legacy/plugins/task_manager/task_manager.mock.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ const createTaskManagerMock = () => {
1010
const mocked: jest.Mocked<TaskManager> = {
1111
registerTaskDefinitions: jest.fn(),
1212
addMiddleware: jest.fn(),
13+
ensureScheduled: jest.fn(),
1314
schedule: jest.fn(),
1415
fetch: jest.fn(),
1516
remove: jest.fn(),

0 commit comments

Comments
 (0)