From 5a0ef763655c25daeacde1f878c99f1073f1a79f Mon Sep 17 00:00:00 2001 From: David Sehnal <david.sehnal@gmail.com> Date: Sun, 10 Dec 2017 20:06:01 +0100 Subject: [PATCH] mol-task aborting --- src/examples/computation.ts | 43 ++++++++++++++++++++++------ src/mol-task/execution/observable.ts | 14 +++++++-- src/mol-task/task.ts | 2 +- 3 files changed, 48 insertions(+), 11 deletions(-) diff --git a/src/examples/computation.ts b/src/examples/computation.ts index 6c3a5e0fa..8068bff31 100644 --- a/src/examples/computation.ts +++ b/src/examples/computation.ts @@ -4,9 +4,9 @@ * @author David Sehnal <david.sehnal@gmail.com> */ -import { Task, Run, Progress, Scheduler } from 'mol-task' +import { Task, Run, Progress, Scheduler, now } from 'mol-task' -async function test() { +export async function test1() { const t = Task.create('test', async () => 1); const r = await Run(t); console.log(r); @@ -26,11 +26,20 @@ function createTask<T>(delayMs: number, r: T): Task<T> { await Scheduler.delay(delayMs); if (ctx.shouldUpdate) await ctx.update({ message: 'hello from delayed... ' }); return r; + }, () => console.log('On abort called ' + r)); +} + +export function abortAfter(delay: number) { + return Task.create('abort after ' + delay, async ctx => { + await Scheduler.delay(delay); + throw Task.Aborted('test'); + //if (ctx.shouldUpdate) await ctx.update({ message: 'hello from delayed... ' }); + //return r; }); } -async function testObs() { - const t = Task.create('test o', async ctx => { +function testTree() { + return Task.create('test o', async ctx => { await Scheduler.delay(250); if (ctx.shouldUpdate) await ctx.update({ message: 'hi! 1' }); await Scheduler.delay(125); @@ -38,17 +47,35 @@ async function testObs() { await Scheduler.delay(250); if (ctx.shouldUpdate) await ctx.update('hi! 3'); - ctx.update('Running children...', true); + // ctx.update('Running children...', true); const c1 = ctx.runChild(createTask(250, 1)); const c2 = ctx.runChild(createTask(500, 2)); const c3 = ctx.runChild(createTask(750, 3)); + + //await ctx.runChild(abortAfter(350)); + const r = await c1 + await c2 + await c3; if (ctx.shouldUpdate) await ctx.update({ message: 'Almost done...' }); return r + 1; }); - const r = await Run(t, p => console.log(messageTree(p.root)), 250); - console.log(r); +} + +export function abortingObserver(p: Progress) { + console.log(messageTree(p.root)); + if (now() - p.root.progress.startedTime > 1000) { + p.requestAbort('test'); + } +} + +async function test() { + try { + //const r = await Run(testTree(), p => console.log(messageTree(p.root)), 250); + const r = await Run(testTree(), abortingObserver, 250); + console.log(r); + } catch (e) { + console.error(e); + } } test(); -testObs(); \ No newline at end of file +//testObs(); \ No newline at end of file diff --git a/src/mol-task/execution/observable.ts b/src/mol-task/execution/observable.ts index 66139e564..8c184c180 100644 --- a/src/mol-task/execution/observable.ts +++ b/src/mol-task/execution/observable.ts @@ -81,10 +81,12 @@ async function execute<T>(task: Task<T>, ctx: ObservableRuntimeContext) { ctx.node.progress.startedTime = now(); try { const ret = await task.__f(ctx); - if (ctx.info.abortToken.abortRequested) abort(ctx.info, ctx.node); + if (ctx.info.abortToken.abortRequested) { + abort(ctx.info, ctx.node); + } return ret; } catch (e) { - if (Task.isAborted(e)) { + if (Task.isAbort(e)) { // wait for all child computations to go thru the abort phase. if (ctx.node.children.length > 0) { await new Promise(res => { ctx.onChildrenFinished = res; }); @@ -193,6 +195,14 @@ class ObservableRuntimeContext implements RuntimeContext { const ctx = new ObservableRuntimeContext(this.info, node); try { return await execute(task, ctx); + } catch (e) { + if (Task.isAbort(e)) { + // need to catch the error here because otherwise + // promises for running child tasks in a tree-like computation + // will get orphaned and cause "uncaught error in Promise". + return void 0 as any; + } + throw e; } finally { // remove the progress node after the computation has finished. const idx = children.indexOf(node); diff --git a/src/mol-task/task.ts b/src/mol-task/task.ts index 64933d25f..0ce5ca40b 100644 --- a/src/mol-task/task.ts +++ b/src/mol-task/task.ts @@ -19,7 +19,7 @@ interface Task<T> { namespace Task { export interface Aborted { isAborted: true, reason: string } - export function isAborted(e: any): e is Aborted { return !!e && !!e.isAborted; } + export function isAbort(e: any): e is Aborted { return !!e && !!e.isAborted; } export function Aborted(reason: string): Aborted { return { isAborted: true, reason }; } export function create<T>(name: string, f: (ctx: RuntimeContext) => Promise<T>, onAbort?: () => void): Task<T> { -- GitLab