Skip to content
Snippets Groups Projects
Commit b79d5b26 authored by David Sehnal's avatar David Sehnal
Browse files

mol-task abort logic

parent 70116624
No related branches found
No related tags found
No related merge requests found
......@@ -13,7 +13,7 @@ import { Scheduler } from '../util/scheduler'
function ExecuteObservable<T>(task: Task<T>, observer: Progress.Observer, updateRateMs = 250) {
const info = ProgressInfo(task, observer, updateRateMs);
const ctx = new ObservableRuntimeContext(info, info.root);
return runRoot(task, ctx);
return execute(task, ctx);
}
namespace ExecuteObservable {
......@@ -38,14 +38,14 @@ interface ProgressInfo {
lastNotified: number,
observer: Progress.Observer,
abortToken: { abortRequested: boolean, reason: string },
abortToken: { abortRequested: boolean, treeAborted: boolean, reason: string },
taskId: number;
root: Progress.Node;
tryAbort: (reason?: string) => void;
}
function ProgressInfo(task: Task<any>, observer: Progress.Observer, updateRateMs: number): ProgressInfo {
const abortToken: ProgressInfo['abortToken'] = { abortRequested: false, reason: '' };
const abortToken: ProgressInfo['abortToken'] = { abortRequested: false, treeAborted: false, reason: '' };
return {
updateRateMs,
......@@ -77,39 +77,42 @@ function snapshotProgress(info: ProgressInfo): Progress {
return { root: cloneTree(info.root), canAbort: canAbort(info.root), requestAbort: info.tryAbort };
}
async function runRoot<T>(task: Task<T>, ctx: ObservableRuntimeContext) {
async function execute<T>(task: Task<T>, ctx: ObservableRuntimeContext) {
ctx.node.progress.startedTime = now();
if (!task.__onAbort) return task.__f(ctx);
try {
const ret = await task.__f(ctx);
// if (ctx.info.abortToken.abortRequested) {
// task.__onAbort();
// }
if (ctx.info.abortToken.abortRequested) abort(ctx.info, ctx.node);
return ret;
} catch (e) {
// TODO: track cancellation
if (Task.isAborted(e)) task.__onAbort();
if (Task.isAborted(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; });
}
if (task.__onAbort) task.__onAbort();
}
if (ExecuteObservable.PRINT_ERRORS_TO_STD_ERR) console.error(e);
throw e;
}
}
async function run<T>(task: Task<T>, ctx: ObservableRuntimeContext) {
ctx.node.progress.startedTime = now();
if (!task.__onAbort) return task.__f(ctx);
try {
const ret = await task.__f(ctx);
// if (ctx.info.abortToken.abortRequested) {
// task.__onAbort();
// }
return ret;
} catch (e) {
if (Task.isAborted(e)) task.__onAbort();
if (ExecuteObservable.PRINT_ERRORS_TO_STD_ERR) console.error(e);
throw e;
function abort(info: ProgressInfo, node: Progress.Node) {
if (!info.abortToken.treeAborted) {
info.abortToken.treeAborted = true;
abortTree(info.root);
notifyObserver(info, now());
}
throw Task.Aborted(info.abortToken.reason);
}
function abortTree(root: Progress.Node) {
const progress = root.progress;
progress.isIndeterminate = true;
progress.canAbort = false;
progress.message = 'Aborting...';
for (const c of root.children) abortTree(c);
}
function shouldNotify(info: ProgressInfo, time: number) {
return time - info.lastNotified > info.updateRateMs;
......@@ -128,9 +131,12 @@ class ObservableRuntimeContext implements RuntimeContext {
node: Progress.Node;
info: ProgressInfo;
// used for waiting for cancelled computation trees
onChildrenFinished?: () => void = void 0;
private checkAborted() {
if (this.info.abortToken.abortRequested) {
throw Task.Aborted(this.info.abortToken.reason);
abort(this.info, this.node);
}
}
......@@ -168,6 +174,10 @@ class ObservableRuntimeContext implements RuntimeContext {
if (!!dontNotify || !shouldNotify(this.info, this.lastUpdatedTime)) return;
notifyObserver(this.info, this.lastUpdatedTime);
// The computation could have been aborted during the notifycation phase.
this.checkAborted();
return Scheduler.immediatePromise();
}
......@@ -182,7 +192,7 @@ class ObservableRuntimeContext implements RuntimeContext {
children.push(node);
const ctx = new ObservableRuntimeContext(this.info, node);
try {
return await run(task, ctx);
return await execute(task, ctx);
} finally {
// remove the progress node after the computation has finished.
const idx = children.indexOf(node);
......@@ -192,6 +202,7 @@ class ObservableRuntimeContext implements RuntimeContext {
}
children.pop();
}
if (children.length === 0 && this.onChildrenFinished) this.onChildrenFinished();
}
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment