Skip to content
This repository has been archived by the owner on Apr 4, 2023. It is now read-only.

Commit

Permalink
Change way of storage runtime info for che tasks
Browse files Browse the repository at this point in the history
Signed-off-by: Roman Nikitenko <[email protected]>
  • Loading branch information
RomanNikitenko committed Sep 27, 2019
1 parent 71951be commit cd671f0
Show file tree
Hide file tree
Showing 7 changed files with 76 additions and 141 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,63 +14,32 @@ import { TaskConfiguration, TaskInfo } from '@eclipse-che/plugin';

@injectable()
export class CheTaskClientImpl implements CheTaskClient {
private readonly onKillEventEmitter: Emitter<number>;
private taskInfoHandlers: ((id: number) => Promise<TaskInfo>)[] = [];
private runTaskHandlers: ((id: number, config: TaskConfiguration, ctx?: string) => Promise<void>)[] = [];
private taskExitedHandlers: ((id: number) => Promise<void>)[] = [];
private readonly onKillEventEmitter: Emitter<TaskInfo>;
private runTaskHandlers: ((config: TaskConfiguration, ctx?: string) => Promise<TaskInfo>)[] = [];

constructor() {
this.onKillEventEmitter = new Emitter<number>();
this.onKillEventEmitter = new Emitter<TaskInfo>();
}

async runTask(id: number, taskConfig: TaskConfiguration, ctx?: string): Promise<void> {
async runTask(taskConfig: TaskConfiguration, ctx?: string): Promise<TaskInfo> {
for (const runTaskHandler of this.runTaskHandlers) {
await runTaskHandler(id, taskConfig, ctx);
}
return undefined;
}

async getTaskInfo(id: number): Promise<TaskInfo | undefined> {
for (const taskInfoHandler of this.taskInfoHandlers) {
try {
const taskInfo = await taskInfoHandler(id);
if (taskInfo) {
return taskInfo;
}
} catch (e) {
// allow another handlers to handle request
const taskInfo = await runTaskHandler(taskConfig, ctx);
if (taskInfo) {
return taskInfo;
}
}
return undefined;
}

async onTaskExited(id: number): Promise<void> {
for (const taskExitedHandler of this.taskExitedHandlers) {
try {
await taskExitedHandler(id);
} catch (e) {
// allow another handlers to handle request
}
}
}

get onKillEvent(): Event<number> {
get onKillEvent(): Event<TaskInfo> {
return this.onKillEventEmitter.event;
}

async killTask(id: number): Promise<void> {
this.onKillEventEmitter.fire(id);
}

addTaskInfoHandler(handler: (id: number) => Promise<TaskInfo>) {
this.taskInfoHandlers.push(handler);
async killTask(taskInfo: TaskInfo): Promise<void> {
this.onKillEventEmitter.fire(taskInfo);
}

addRunTaskHandler(handler: (id: number, config: TaskConfiguration, ctx?: string) => Promise<void>) {
addRunTaskHandler(handler: (config: TaskConfiguration, ctx?: string) => Promise<TaskInfo>) {
this.runTaskHandlers.push(handler);
}

addTaskExitedHandler(handler: (id: number) => Promise<void>) {
this.taskExitedHandlers.push(handler);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,10 @@ export class CheTaskMainImpl implements CheTaskMain {
const proxy: CheTask = rpc.getProxy(PLUGIN_RPC_CONTEXT.CHE_TASK);
this.delegate = container.get(CheTaskService);
this.cheTaskClient = container.get(CheTaskClient);
this.cheTaskClient.onKillEvent(id => proxy.$killTask(id));
this.cheTaskClient.addTaskInfoHandler(id => proxy.$getTaskInfo(id));
this.cheTaskClient.addTaskExitedHandler(id => proxy.$onTaskExited(id));
this.cheTaskClient.addRunTaskHandler((id, config, ctx) => proxy.$runTask(id, config, ctx));
this.cheTaskClient.onKillEvent(taskInfo => proxy.$killTask(taskInfo));
this.cheTaskClient.addRunTaskHandler((config, ctx) => proxy.$runTask(config, ctx));
}

$registerTaskRunner(type: string): Promise<void> {
return this.delegate.registerTaskRunner(type);
}
Expand Down
18 changes: 6 additions & 12 deletions extensions/eclipse-che-theia-plugin-ext/src/common/che-protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,8 @@ export interface CheVariablesMain {
export interface CheTask {
registerTaskRunner(type: string, runner: che.TaskRunner): Promise<che.Disposable>;
fireTaskExited(event: che.TaskExitedEvent): Promise<void>;
$runTask(id: number, config: che.TaskConfiguration, ctx?: string): Promise<void>;
$onTaskExited(id: number): Promise<void>;
$killTask(id: number): Promise<void>;
$getTaskInfo(id: number): Promise<che.TaskInfo | undefined>;
$runTask(config: che.TaskConfiguration, ctx?: string): Promise<che.TaskInfo>;
$killTask(taskInfo: che.TaskInfo): Promise<void>;
}

export const CheTaskMain = Symbol('CheTaskMain');
Expand Down Expand Up @@ -416,14 +414,10 @@ export interface CheTaskService extends JsonRpcServer<CheTaskClient> {

export const CheTaskClient = Symbol('CheTaskClient');
export interface CheTaskClient {
runTask(id: number, taskConfig: che.TaskConfiguration, ctx?: string): Promise<void>;
killTask(id: number): Promise<void>;
getTaskInfo(id: number): Promise<che.TaskInfo | undefined>;
onTaskExited(id: number): Promise<void>;
addTaskInfoHandler(func: (id: number) => Promise<che.TaskInfo | undefined>): void;
addRunTaskHandler(func: (id: number, config: che.TaskConfiguration, ctx?: string) => Promise<void>): void;
addTaskExitedHandler(func: (id: number) => Promise<void>): void;
onKillEvent: Event<number>
runTask(taskConfig: che.TaskConfiguration, ctx?: string): Promise<che.TaskInfo>;
killTask(taskInfo: che.TaskInfo): Promise<void>;
addRunTaskHandler(func: (config: che.TaskConfiguration, ctx?: string) => Promise<che.TaskInfo>): void;
onKillEvent: Event<che.TaskInfo>
}

export interface ChePluginRegistry {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,12 @@ export class CheTaskServiceImpl implements CheTaskService {
private readonly disposableMap: Map<string, Disposable>;
private readonly cheTasks: CheTask[] = [];
private readonly clients: CheTaskClient[];
private taskId: number;
constructor(container: interfaces.Container) {
this.runnerRegistry = container.get(TaskRunnerRegistry);
this.taskManager = container.get(TaskManager);
this.logger = container.get(ILogger);
this.disposableMap = new Map();
this.clients = [];
this.taskId = 0;
}

async registerTaskRunner(type: string): Promise<void> {
Expand All @@ -40,13 +38,14 @@ export class CheTaskServiceImpl implements CheTaskService {
};
this.disposableMap.set(type, this.runnerRegistry.registerRunner(type, runner));
const runTask = async (config: TaskConfiguration, ctx?: string): Promise<Task> => {
const id = this.taskId++;
for (const client of this.clients) {
await client.runTask(id, config, ctx);
const taskInfo = await client.runTask(config, ctx);
const options: CheTaskOptions = { label: config.label, config, context: ctx, runtimeInfo: taskInfo };

const cheTask = new CheTask(this.taskManager, this.logger, this.clients, options);
this.cheTasks.push(cheTask);
return cheTask;
}
const cheTask = new CheTask(id, this.taskManager, this.logger, { label: config.label, config, context: ctx }, this.clients);
this.cheTasks.push(cheTask);
return cheTask;
};
}

Expand Down Expand Up @@ -74,57 +73,45 @@ export class CheTaskServiceImpl implements CheTaskService {

async fireTaskExited(event: TaskExitedEvent): Promise<void> {
for (const task of this.cheTasks) {
try {
const runtimeInfo = await task.getRuntimeInfo();
if (runtimeInfo.execId === event.execId || runtimeInfo.taskId === event.taskId) {

task.fireTaskExited({ taskId: task.id, code: event.code, ctx: runtimeInfo.ctx });
const runtimeInfo = task.getRuntimeInfo();
if (runtimeInfo.execId === event.execId || runtimeInfo.taskId === event.taskId) {

task.onTaskExited();
task.fireTaskExited({ taskId: task.id, code: event.code, ctx: runtimeInfo.ctx });

const index = this.cheTasks.indexOf(task);
if (index > -1) {
this.cheTasks.splice(index, 1);
}
break;
const index = this.cheTasks.indexOf(task);
if (index > -1) {
this.cheTasks.splice(index, 1);
}
} catch (e) {
// allow another handlers to handle request
break;
}
}
}
}

export interface CheTaskOptions extends TaskOptions {
runtimeInfo: TaskInfo;
}

class CheTask extends Task {
private readonly clients: CheTaskClient[];
constructor(id: number,
private taskInfo: TaskInfo;
constructor(
taskManager: TaskManager,
logger: ILogger,
options: TaskOptions,
clients: CheTaskClient[]) {
clients: CheTaskClient[],
options: CheTaskOptions) {

super(taskManager, logger, options);
this.clients = clients;
this.taskId = id;
this.taskInfo = this.toTaskInfo(options.runtimeInfo);
}

async getRuntimeInfo(): Promise<TaskInfo> {
for (const client of this.clients) {
const taskInfo = await client.getTaskInfo(this.taskId);
if (taskInfo) {
return this.toTaskInfo(taskInfo);
}
}
throw new Error(`Runtime Information for task ${this.options.label} is not found`);
}

async onTaskExited(): Promise<void> {
for (const client of this.clients) {
await client.onTaskExited(this.taskId);
}
getRuntimeInfo(): TaskInfo {
return this.taskInfo;
}

async kill(): Promise<void> {
this.clients.forEach(client => client.killTask(this.taskId));
this.clients.forEach(client => client.killTask(this.taskInfo));
}

fireTaskExited(event: TaskExitedEvent): void {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,15 @@
* SPDX-License-Identifier: EPL-2.0
**********************************************************************/
import { CheTask, CheTaskMain, PLUGIN_RPC_CONTEXT } from '../common/che-protocol';
import { TaskRunner, Disposable, Task, TaskInfo, TaskExitedEvent, TaskConfiguration } from '@eclipse-che/plugin';
import { TaskRunner, Disposable, TaskInfo, TaskExitedEvent, TaskConfiguration } from '@eclipse-che/plugin';
import { RPCProtocol } from '@theia/plugin-ext/lib/common/rpc-protocol';

export class CheTaskImpl implements CheTask {
private readonly cheTaskMain: CheTaskMain;
private readonly runnerMap: Map<string, TaskRunner>;
private readonly taskMap: Map<number, Task>;
constructor(rpc: RPCProtocol) {
this.cheTaskMain = rpc.getProxy(PLUGIN_RPC_CONTEXT.CHE_TASK_MAIN);
this.runnerMap = new Map();
this.taskMap = new Map();
}
async registerTaskRunner(type: string, runner: TaskRunner): Promise<Disposable> {
this.runnerMap.set(type, runner);
Expand All @@ -30,33 +28,17 @@ export class CheTaskImpl implements CheTask {
};
}

async $runTask(id: number, config: TaskConfiguration, ctx?: string): Promise<void> {
async $runTask(config: TaskConfiguration, ctx?: string): Promise<TaskInfo> {
const runner = this.runnerMap.get(config.type);
if (runner) {
const task = await runner.run(config, ctx);
this.taskMap.set(id, task);
return await runner.run(config, ctx);
}
}

async $killTask(id: number): Promise<void> {
const task = this.taskMap.get(id);
if (task) {
await task.kill();
this.taskMap.delete(id);
}
}

async $getTaskInfo(id: number): Promise<TaskInfo | undefined> {
const task = this.taskMap.get(id);
if (task) {
return task.getRuntimeInfo();
}
}

async $onTaskExited(id: number): Promise<void> {
const task = this.taskMap.get(id);
if (task) {
this.taskMap.delete(id);
async $killTask(taskInfo: TaskInfo): Promise<void> {
const runner = this.runnerMap.get(taskInfo.config.type);
if (runner) {
return await runner.kill(taskInfo);
}
}

Expand Down
11 changes: 3 additions & 8 deletions extensions/eclipse-che-theia-plugin/src/che-proposed.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,14 +112,9 @@ declare module '@eclipse-che/plugin' {
/** A Task Runner knows how to run a Task of a particular type. */
export interface TaskRunner {
/** Runs a task based on the given task configuration. */
run(taskConfig: TaskConfiguration, ctx?: string): Promise<Task>;
}

export interface Task {
/** Terminates the task. */
kill(): Promise<void>;
/** Returns runtime information about task. */
getRuntimeInfo(): TaskInfo;
run(taskConfig: TaskConfiguration, ctx?: string): Promise<TaskInfo>;
/** Terminates a task based on the given info. */
kill(taskInfo: TaskInfo): Promise<void>;
}

/** Runtime information about Task. */
Expand Down
31 changes: 20 additions & 11 deletions plugins/task-plugin/src/task/che-task-runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export class CheTaskRunner {
/**
* Runs a task from the given task configuration which must have a target property specified.
*/
async run(taskConfig: che.TaskConfiguration, ctx?: string): Promise<che.Task> {
async run(taskConfig: che.TaskConfiguration, ctx?: string): Promise<che.TaskInfo> {
const { type, label, ...definition } = taskConfig;
if (type !== CHE_TASK_TYPE) {
throw new Error(`Unsupported task type: ${type}`);
Expand Down Expand Up @@ -77,20 +77,29 @@ export class CheTaskRunner {
const execId = await terminal.processId;

return {
kill: () => {
throw new Error('Stopping a Che task currently is not supported.');
},
getRuntimeInfo: () =>
({
taskId: STUB_TASK_ID,
ctx: ctx,
config: taskConfig,
execId: execId
})
taskId: STUB_TASK_ID,
ctx: ctx,
config: taskConfig,
execId: execId
};
} catch (error) {
console.error('Failed to execute Che command:', error);
throw new Error(`Failed to execute Che command: ${error.message}`);
}
}

/** Terminates a task based on the given info. */
async kill(taskInfo: che.TaskInfo): Promise<void> {
for (const terminal of theia.window.terminals) {
try {
const processId = await terminal.processId;
if (processId === taskInfo.execId) {
terminal.sendText('\x03');
return;
}
} catch (e) {
// allow to get process id for other terminals
}
}
}
}

0 comments on commit cd671f0

Please sign in to comment.