Skip to content

Commit

Permalink
Merge pull request #14 from tabkram/engine-decorators
Browse files Browse the repository at this point in the history
feat: add execution engine decorators @engine() and @run()
  • Loading branch information
tabkram committed Dec 10, 2023
2 parents e1eeca3 + 447fec9 commit 10dfdac
Show file tree
Hide file tree
Showing 16 changed files with 846 additions and 48 deletions.
69 changes: 42 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,62 +34,82 @@ yarn add execution-engine

## Usage 📚

- example:
### Example 1: Basic Usage

```typescript
import { ExecutionEngine } from "execution-engine";

const engine = new ExecutionEngine();

// for sync functions:
const result1 = engine.run((param) => `result1 for ${param}`, ['param1']);
const res1 = engine.run((param) => `result1 for ${param}`, ['param1']);

// for async functions:
const result2 = await engine.run(async (param) => `result2 for ${param}`, [result1.outputs]);
const res2 = await engine.run(async (param) => `result2 for ${param}`, [res1.outputs]);

// Retrieve the trace
const trace = engine.getTrace();
console.log('Trace:', trace);
```

- The `result` object contains function output (`outputs`), input parameters (`inputs`), and other attributes related to
the engine. It has the following structure:
You can:

- view the **complete code** in [examples/usage.ts](examples/usage.ts)
- inspect the **trace output** in [examples/usage.json](examples/usage.json).
- visualize the **trace graph** using the json-to-graph online tool. [→ See the result ←](https://tabkram.github.io/json-to-graph/?data=https://raw.githubusercontent.com/tabkram/execution-engine/main/examples/usage.json)

### Example 2: Usage with Decorators

```typescript
result = {
// An array containing the input values passed to thunction:
inputs: [
"param1"
],
// The output value returned by the function:
outputs: "result1 for param1",
// The start time of the function execution:
startTime: Date,
// The end time of the function execution:
endTime: Date,
// The duration of the function execution in milliseconds:
duration: number,
// ...other properties depending on the configuration and trace options.
import { engine, run } from "execution-engine";

@engine({ id: "uniqueEngineId" })
class MyClass extends EngineTask {
@run()
myMethod1(param: string) {
return `result1 for ${param}`;
}

@run()
async myMethod2(param: string) {
return `result2 for ${param}`;
}
}

const myInstance = new MyClass();
myInstance.myMethod2("param1");
await myInstance.myMethod2("param2");

// Retrieve the trace
const trace = myInstance.engine.getTrace();
console.log("Trace:", trace);
```

- The `trace` object is an array containing **nodes** and **edges**. It has the following structure:
You can:

- view the **complete code** in [examples/usage2.ts](examples/usage2.ts)
- inspect the **trace output** in [examples/usage2.json](examples/usage2.json)
- visualize the **trace graph** using the json-to-graph online tool. [→ See the result ←](https://tabkram.github.io/json-to-graph/?data=https://raw.githubusercontent.com/tabkram/execution-engine/main/examples/usage2.json)

### Understanding the Trace 🧭

The `trace` object is an array containing **nodes** and **edges**. It has the following structure:

```typescript
trace = [
{
data: {
id: function_uuid1,
label: "function"
//... other properties of the "result1" of the executed function as mentioned above
//... other properties of the result of the executed function as mentioned above
},
group: nodes
},
{
data: {
id: function_uuid2,
label: "function"
//... other properties of the "result2" of the executed function as mentioned above
//... other properties of the result of the executed function as mentioned above
},
group: nodes
},
Expand All @@ -105,11 +125,6 @@ trace = [
];
```

- Visualize the `trace` object using the json-to-graph online tool. [→ See the result ←](https://tabkram.github.io/json-to-graph/?data=https://raw.githubusercontent.com/tabkram/execution-engine/main/examples/usage.json)

You can view the complete code in [examples/usage.ts](examples/usage.ts) and inspect the entire trace output
in [examples/usage.json](examples/usage.json).

## Examples 📘

For additional usage examples, please explore the __[/examples](examples)__ directory in this repository.
Expand Down
45 changes: 45 additions & 0 deletions docs/EngineTask.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# EngineTask

The `EngineTask` class represents an abstract task with a reference to the `ExecutionEngine`. It serves as a base class for integrating execution engine capabilities into other classes.

## @engine Decorator

The `@engine` decorator enhances a class with execution engine capabilities. It takes a configuration object as an argument, allowing you to customize the behavior of the associated engine.

### Usage

```typescript
@engine({ id: "uniqueEngineId" })
class MyClass extends EngineTask {
// Class implementation
}
```

#### Explanation

The `@engine` decorator is applied to a class to inject execution engine capabilities. The configuration object passed as an argument provides a unique identifier (`id`) for the associated engine. This allows multiple classes to use different engines, each with its own configuration.

## @run Decorator

The `@run` decorator enables tracing for decorated methods. It takes trace options as an optional argument, allowing you to fine-tune the tracing behavior.

### Usage

```typescript
class MyClass extends EngineTask {
@run()
myMethod1(param: string) {
// Method implementation
}

@run()
async myMethod2(param: string) {
// Async method implementation
}
```
#### Explanation
The `@run` decorator is applied to methods within a class to enable tracing for their executions. The optional trace options allow you to customize the tracing behavior for specific methods. For example, you can configure whether a method should be traced asynchronously or set additional options for the trace.
This section provides a detailed explanation of how to use the `@engine` and `@run` decorators along with the `EngineTask` class. By understanding the purpose and usage of these decorators, you can effectively integrate execution engine features and tracing into your TypeScript classes, tailoring them to the specific requirements of your project. Adjust the import statements and decorator parameters based on your actual implementation.
76 changes: 76 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,79 @@ A TypeScript library for tracing and visualizing code execution workflows

## Installation 📦

Use [npm](https://www.npmjs.com/package/execution-engine) package manager:

```bash
npm install execution-engine
```

Or use the [yarn](https://yarnpkg.com/package?name=execution-engine) package manager:

```bash
yarn add execution-engine
```

## Usage 📚

### Example 1: Basic Usage

```typescript
import { ExecutionEngine } from "execution-engine";

const engine = new ExecutionEngine();

// for sync functions:
const res1 = engine.run((param) => `result1 for ${param}`, ['param1']);

// for async functions:
const res2 = await engine.run(async (param) => `result2 for ${param}`, [res1.outputs]);

// Retrieve the trace
const trace = engine.getTrace();
console.log('Trace:', trace);
```

You can:

- view the **complete code** in [examples/usage.ts](examples/usage.ts)
- inspect the **trace output** in [examples/usage.json](examples/usage.json).
- visualize the **trace graph** using the json-to-graph online
tool. [→ See the result ←](https://tabkram.github.io/json-to-graph/?data=https://raw.githubusercontent.com/tabkram/execution-engine/main/examples/usage.json)

### Example 2: Usage with Decorators

```typescript
import { engine, run } from "execution-engine";

@engine({ id: "uniqueEngineId" })
class MyClass extends EngineTask {
@run()
myMethod1(param: string) {
return `result1 for ${param}`;
}

@run()
async myMethod2(param: string) {
return `result2 for ${param}`;
}
}

const myInstance = new MyClass();
myInstance.myMethod2("param1");
await myInstance.myMethod2("param2");

// Retrieve the trace
const trace = myInstance.engine.getTrace();
console.log("Trace:", trace);
```

You can:

- view the **complete code** in [examples/usage2.ts](examples/usage2.ts)
- inspect the **trace output** in [examples/usage2.json](examples/usage2.json)
- visualize the **trace graph** using the json-to-graph online
tool. [→ See the result ←](https://tabkram.github.io/json-to-graph/?data=https://raw.githubusercontent.com/tabkram/execution-engine/main/examples/usage2.json)

## Components 🧩

### ExecutionTimer
Expand All @@ -35,3 +104,10 @@ The __[ExecutionEngine](./ExecutionEngine.md)__ enhances traceable execution by
capturing additional relevant information.
It builds upon the functionality of [TraceableExecution](./TraceableExecution.md).

### EngineTask Class and @engine/@run Decorators

The __[EngineTask](./EngineTask.md)__ class works in conjunction with the `@engine` decorator and the `@run` decorator
to integrate the ExecutionEngine into your classes, providing tracing capabilities for methods.

For more details and usage examples, refer to the source code in __[EngineTask](./EngineTask.md)__.

6 changes: 3 additions & 3 deletions examples/usage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ export async function run() {
const engine = new ExecutionEngine();

// for sync functions:
const result1 = engine.run((param) => `result1 for ${param}`, ['param1']);
const res1 = engine.run((param) => `result1 for ${param}`, ['param1']);

// for async functions:
const result2 = await engine.run(async (param) => `result2 for ${param}`, [result1.outputs]);
const res2 = await engine.run(async (param) => `result2 for ${param}`, [res1.outputs]);

// Retrieve the trace
const trace = engine.getTrace();
const jsonString = JSON.stringify(trace, null, 2);
writeTrace(jsonString);
}

run();
run().then();
47 changes: 47 additions & 0 deletions examples/usage2.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
[
{
"data": {
"id": "bound myMethod1_1702207617652_13a5a286-3150-4950-b67a-8e03a797b770",
"label": "bound myMethod1",
"inputs": [
"param1"
],
"outputs": "result1 for param1",
"startTime": "2023-12-10T11:26:57.652Z",
"endTime": "2023-12-10T11:26:57.653Z",
"duration": 0.40799999237060547,
"elapsedTime": "0.408 ms",
"parallel": false,
"abstract": false,
"createTime": "2023-12-10T11:26:57.653Z"
},
"group": "nodes"
},
{
"data": {
"id": "bound myMethod2_1702207617653_daeb25cd-1822-48d8-9744-a460bfe9f82f",
"label": "bound myMethod2",
"inputs": [
"param2"
],
"outputs": "result2 for param2",
"startTime": "2023-12-10T11:26:57.653Z",
"endTime": "2023-12-10T11:26:57.653Z",
"duration": 0.2049999237060547,
"elapsedTime": "0.205 ms",
"parallel": false,
"abstract": false,
"createTime": "2023-12-10T11:26:57.653Z"
},
"group": "nodes"
},
{
"data": {
"id": "bound myMethod1_1702207617652_13a5a286-3150-4950-b67a-8e03a797b770->bound myMethod2_1702207617653_daeb25cd-1822-48d8-9744-a460bfe9f82f",
"source": "bound myMethod1_1702207617652_13a5a286-3150-4950-b67a-8e03a797b770",
"target": "bound myMethod2_1702207617653_daeb25cd-1822-48d8-9744-a460bfe9f82f",
"parallel": false
},
"group": "edges"
}
]
28 changes: 28 additions & 0 deletions examples/usage2.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { engine, EngineTask, run } from '../src';
import { writeTrace } from './common/writeTrace';

@engine({ id: 'uniqueEngineId' })
class MyClass extends EngineTask {
@run()
myMethod1(param: string) {
return `result1 for ${param}`;
}

@run()
async myMethod2(param: string) {
return `result2 for ${param}`;
}
}

export async function generate() {
const myInstance = new MyClass();
myInstance.myMethod1('param1');
await myInstance.myMethod2('param2');

// Retrieve the trace
const trace = myInstance.engine.getTrace();
const jsonString = JSON.stringify(trace, null, 2);
writeTrace(jsonString);
}

generate().then();
Loading

1 comment on commit 10dfdac

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Coverage report

St.
Category Percentage Covered / Total
🟢 Statements 92.22% 237/257
🟢 Branches 86.57% 174/201
🟢 Functions 91.67% 66/72
🟢 Lines 92.95% 224/241

Test suite run success

32 tests passing in 5 suites.

Report generated by 🧪jest coverage report action from 10dfdac

Please sign in to comment.