-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #438 from MatrixAI/feature-queue
Feature TaskManager Scheduler and Queue and Context Decorators for Timed and Cancellable
- Loading branch information
Showing
38 changed files
with
7,692 additions
and
104 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import type { ContextCancellable } from '../types'; | ||
import { setupCancellable } from '../functions/cancellable'; | ||
import * as contextsUtils from '../utils'; | ||
|
||
function cancellable(lazy: boolean = false) { | ||
return < | ||
T extends TypedPropertyDescriptor< | ||
(...params: Array<any>) => PromiseLike<any> | ||
>, | ||
>( | ||
target: any, | ||
key: string | symbol, | ||
descriptor: T, | ||
): T => { | ||
// Target is instance prototype for instance methods // or the class prototype for static methods | ||
const targetName = target['name'] ?? target.constructor.name; | ||
const f = descriptor['value']; | ||
if (typeof f !== 'function') { | ||
throw new TypeError( | ||
`\`${targetName}.${key.toString()}\` is not a function`, | ||
); | ||
} | ||
const contextIndex = contextsUtils.getContextIndex(target, key, targetName); | ||
descriptor['value'] = function (...args) { | ||
let ctx: Partial<ContextCancellable> = args[contextIndex]; | ||
if (ctx === undefined) { | ||
ctx = {}; | ||
args[contextIndex] = ctx; | ||
} | ||
// Runtime type check on the context parameter | ||
contextsUtils.checkContextCancellable(ctx, key, targetName); | ||
return setupCancellable( | ||
(_, ...args) => f.apply(this, args), | ||
lazy, | ||
ctx, | ||
args, | ||
); | ||
}; | ||
// Preserve the name | ||
Object.defineProperty(descriptor['value'], 'name', { | ||
value: typeof key === 'symbol' ? `[${key.description}]` : key, | ||
}); | ||
return descriptor; | ||
}; | ||
} | ||
|
||
export default cancellable; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import * as contextsUtils from '../utils'; | ||
|
||
/** | ||
* Context parameter decorator | ||
* It is only allowed to be used once | ||
*/ | ||
function context(target: any, key: string | symbol, index: number) { | ||
const targetName = target['name'] ?? target.constructor.name; | ||
const method = target[key]; | ||
if (contextsUtils.contexts.has(method)) { | ||
throw new TypeError( | ||
`\`${targetName}.${key.toString()}\` redeclares \`@context\` decorator`, | ||
); | ||
} | ||
contextsUtils.contexts.set(method, index); | ||
} | ||
|
||
export default context; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
export { default as context } from './context'; | ||
export { default as cancellable } from './cancellable'; | ||
export { default as timed } from './timed'; | ||
export { default as timedCancellable } from './timedCancellable'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
import type { ContextTimed } from '../types'; | ||
import { setupTimedContext } from '../functions/timed'; | ||
import * as contextsUtils from '../utils'; | ||
import * as contextsErrors from '../errors'; | ||
import * as utils from '../../utils'; | ||
|
||
/** | ||
* Timed method decorator | ||
*/ | ||
function timed( | ||
delay: number = Infinity, | ||
errorTimeoutConstructor: new () => Error = contextsErrors.ErrorContextsTimedTimeOut, | ||
) { | ||
return ( | ||
target: any, | ||
key: string | symbol, | ||
descriptor: TypedPropertyDescriptor<(...params: Array<any>) => any>, | ||
) => { | ||
// Target is instance prototype for instance methods | ||
// or the class prototype for static methods | ||
const targetName = target['name'] ?? target.constructor.name; | ||
const f = descriptor['value']; | ||
if (typeof f !== 'function') { | ||
throw new TypeError( | ||
`\`${targetName}.${key.toString()}\` is not a function`, | ||
); | ||
} | ||
const contextIndex = contextsUtils.getContextIndex(target, key, targetName); | ||
if (f instanceof utils.AsyncFunction) { | ||
descriptor['value'] = async function (...args) { | ||
let ctx: Partial<ContextTimed> = args[contextIndex]; | ||
if (ctx === undefined) { | ||
ctx = {}; | ||
args[contextIndex] = ctx; | ||
} | ||
// Runtime type check on the context parameter | ||
contextsUtils.checkContextTimed(ctx, key, targetName); | ||
const teardownContext = setupTimedContext( | ||
delay, | ||
errorTimeoutConstructor, | ||
ctx, | ||
); | ||
try { | ||
return await f.apply(this, args); | ||
} finally { | ||
teardownContext(); | ||
} | ||
}; | ||
} else if (f instanceof utils.GeneratorFunction) { | ||
descriptor['value'] = function* (...args) { | ||
let ctx: Partial<ContextTimed> = args[contextIndex]; | ||
if (ctx === undefined) { | ||
ctx = {}; | ||
args[contextIndex] = ctx; | ||
} | ||
// Runtime type check on the context parameter | ||
contextsUtils.checkContextTimed(ctx, key, targetName); | ||
const teardownContext = setupTimedContext( | ||
delay, | ||
errorTimeoutConstructor, | ||
ctx, | ||
); | ||
try { | ||
return yield* f.apply(this, args); | ||
} finally { | ||
teardownContext(); | ||
} | ||
}; | ||
} else if (f instanceof utils.AsyncGeneratorFunction) { | ||
descriptor['value'] = async function* (...args) { | ||
let ctx: Partial<ContextTimed> = args[contextIndex]; | ||
if (ctx === undefined) { | ||
ctx = {}; | ||
args[contextIndex] = ctx; | ||
} | ||
// Runtime type check on the context parameter | ||
contextsUtils.checkContextTimed(ctx, key, targetName); | ||
const teardownContext = setupTimedContext( | ||
delay, | ||
errorTimeoutConstructor, | ||
ctx, | ||
); | ||
try { | ||
return yield* f.apply(this, args); | ||
} finally { | ||
teardownContext(); | ||
} | ||
}; | ||
} else { | ||
descriptor['value'] = function (...args) { | ||
let ctx: Partial<ContextTimed> = args[contextIndex]; | ||
if (ctx === undefined) { | ||
ctx = {}; | ||
args[contextIndex] = ctx; | ||
} | ||
// Runtime type check on the context parameter | ||
contextsUtils.checkContextTimed(ctx, key, targetName); | ||
const teardownContext = setupTimedContext( | ||
delay, | ||
errorTimeoutConstructor, | ||
ctx, | ||
); | ||
const result = f.apply(this, args); | ||
if (utils.isPromiseLike(result)) { | ||
return result.then( | ||
(r) => { | ||
teardownContext(); | ||
return r; | ||
}, | ||
(e) => { | ||
teardownContext(); | ||
throw e; | ||
}, | ||
); | ||
} else if (utils.isGenerator(result)) { | ||
return (function* () { | ||
try { | ||
return yield* result; | ||
} finally { | ||
teardownContext(); | ||
} | ||
})(); | ||
} else if (utils.isAsyncGenerator(result)) { | ||
return (async function* () { | ||
try { | ||
return yield* result; | ||
} finally { | ||
teardownContext(); | ||
} | ||
})(); | ||
} else { | ||
teardownContext(); | ||
return result; | ||
} | ||
}; | ||
} | ||
// Preserve the name | ||
Object.defineProperty(descriptor['value'], 'name', { | ||
value: typeof key === 'symbol' ? `[${key.description}]` : key, | ||
}); | ||
return descriptor; | ||
}; | ||
} | ||
|
||
export default timed; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
import type { ContextTimed } from '../types'; | ||
import { setupTimedCancellable } from '../functions/timedCancellable'; | ||
import * as contextsUtils from '../utils'; | ||
import * as contextsErrors from '../errors'; | ||
|
||
function timedCancellable( | ||
lazy: boolean = false, | ||
delay: number = Infinity, | ||
errorTimeoutConstructor: new () => Error = contextsErrors.ErrorContextsTimedTimeOut, | ||
) { | ||
return < | ||
T extends TypedPropertyDescriptor< | ||
(...params: Array<any>) => PromiseLike<any> | ||
>, | ||
>( | ||
target: any, | ||
key: string | symbol, | ||
descriptor: T, | ||
) => { | ||
// Target is instance prototype for instance methods | ||
// or the class prototype for static methods | ||
const targetName: string = target['name'] ?? target.constructor.name; | ||
const f = descriptor['value']; | ||
if (typeof f !== 'function') { | ||
throw new TypeError( | ||
`\`${targetName}.${key.toString()}\` is not a function`, | ||
); | ||
} | ||
const contextIndex = contextsUtils.getContextIndex(target, key, targetName); | ||
descriptor['value'] = function (...args) { | ||
let ctx: Partial<ContextTimed> = args[contextIndex]; | ||
if (ctx === undefined) { | ||
ctx = {}; | ||
args[contextIndex] = ctx; | ||
} | ||
// Runtime type check on the context parameter | ||
contextsUtils.checkContextTimed(ctx, key, targetName); | ||
return setupTimedCancellable( | ||
(_, ...args) => f.apply(this, args), | ||
lazy, | ||
delay, | ||
errorTimeoutConstructor, | ||
ctx, | ||
args, | ||
); | ||
}; | ||
// Preserve the name | ||
Object.defineProperty(descriptor['value'], 'name', { | ||
value: typeof key === 'symbol' ? `[${key.description}]` : key, | ||
}); | ||
return descriptor; | ||
}; | ||
} | ||
|
||
export default timedCancellable; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import { ErrorPolykey, sysexits } from '../errors'; | ||
|
||
class ErrorContexts<T> extends ErrorPolykey<T> {} | ||
|
||
class ErrorContextsTimedTimeOut<T> extends ErrorContexts<T> { | ||
static description = 'Aborted due to timer expiration'; | ||
exitCode = sysexits.UNAVAILABLE; | ||
} | ||
|
||
export { ErrorContexts, ErrorContextsTimedTimeOut }; |
Oops, something went wrong.