# Step

### How To Use

Packhouse本體只是個函數設計模型，而Step負責建構`middleware`與流程設計使得Packhouse具有實際建構服務的能力。

Step是一個[Plugin](/the-instance/plugin.md)，使用前必須先引用：

```javascript
let Step = require('packhouse/plugins/Step')
let Packhouse = require('packhouse')
let packhouse = new Packhouse()

packhouse.plugin(Step)
```

{% hint style="info" %}
與其說本頁面是教學更像是說明文件，實際的應用方式可以直接參照[API Service](/application/api-service.md)。
{% endhint %}

## Flow

整個flow是經由下列控制：

* `next`下一步。
* `exit`跳出至`output`，可以攜帶一個參數，會傳遞至`output`的`message`。
* `fail`跳出至`output`，但`fail`為`true`，可以攜帶一個參數，會傳遞至`output`的`message`。

```javascript
let step = packhouse.step({
    timeout: 25000, // ms
    create: function(self, { exit, fail }) {
        self.result = 0
    },
    middle: function(self, { exit, fail }) {
        if (typeof self.result !== 'number') {
            exit()
        }
    },
    // required
    output(self, { timeout, history, fail, message }, done, error) {
        done(self.result)
    },
    // required
    template: [
        function add(self, next, { exit, fail }) {
            self.result = 10
            next()
        },
        function double(self, next) {
            self.result *= 2
            next()
        }
    ]
})

step.then((result) => {
    console.log(result) // 20
})
```

上面的程式的運作如下：

<div align="left"><img src="/files/-LwYsJGuPwnxtz_0NXex" alt=""></div>

### Create

第一次執行Step時觸發的方法，必須是同步的函數，可以執行跳出事件。

### Middle

`create -> template -> output` 行為之間都會出發`middle`，可以作為跳出判定層，必須是同步函數。

### Output

接收所有運算結果的地方，為非同步函數，最後兩個參數為`done`與`error`，決定整個Step為`reslove`還是`reject`。

```javascript
const output = (self, { timeout, history, fail, message }, done, error) => {
    done('success!')
}
```

### Timeout

指定運行的毫秒數，如果省略則無限制，當運行時間超過時會無條件呼叫`output`，且`timeout`為`true`。

{% hint style="info" %}
由於`output`有可能需要處裡請求事件，Timeout的設計並不包含該流程的時間，在AWS APIGateway開發的過程需要注意只能運行30秒的限制。
{% endhint %}

```javascript
const output = (self, { timeout}, done, error) => {
    console.log(timeout) // true or false
}
```

### Fail

當呼叫`output`的對象是`fail`時為`true`。

### Message

當`fail`或`exit`有攜帶參數時會帶入的值。

### Template

運作的過程，與[`async waterfall`](https://caolan.github.io/async/v3/docs.html#waterfall)雷同，會隨著陣列的順序依序宣告，執行到最末端後執行`output`，也允許執行跳出整個流程。

### History

記錄整個執行過程的物件，可輸出`JSON Log`。

```javascript
{
    profile: 'object',
    template: 'template log',
    isDone: 'function',
    toJSON: 'function'
}
```

#### Profile

| Key        | Value           |
| ---------- | --------------- |
| fail       | 是否為Fail         |
| message    | 同output message |
| timeout    | 是否為timeout      |
| startTime  | 起始時間            |
| finishTime | 結束時間            |
| totalTime  | 總運行時間(ms)       |

#### Template

整體運作的細部資料，除非不得已，否則我們建議使用[ToJSON](/plugins/step.md#to-json)來檢視整個過程。

#### Is Done

如果有對Template的函數進行命名，可以使用`isDone`來驗證是否有運行該函數。

```javascript
const step = {
    template: [
        function myFunction(self, next, { exit }) {
            exit()
        },
        function myFunction2(self, next) {
            next()
        }
    ],
    output(self, { history }, done) {
        console.log(history.isDone('myFunction')) // true
        console.log(history.isDone('myFunction2')) // false
        done()
    }
}
```

#### To JSON

將細部運作資料轉換成JSON可存放資料。

{% hint style="info" %}
輸出的資料將是個大型的JSON文件，尤其是在參數與回傳值非常龐大的情況下，請自行評估何時運作`toJSON`來確保是否佔用太多資源。
{% endhint %}

```javascript
let Step = require('packhouse/plugins/Step')
let Packhouse = require('packhouse')
let packhouse = new Packhouse()

packhouse.plugin(Step)
packhouse.addGroup('math', () => {
    return {
        data: {
            tools: {
                sum: {
                    handler(self, v1, v2) {
                        self.success(v1 + v2)
                    }
                }
            }
        }
    }
})

packhouse.step({
    template: [
        function sum(self, done) {
            packhouse.tool('math/sum').action(10, 20, () => {
                done()
            })
        }
    ],
    output(self, { history }, done) {
        console.log(history.toJSON({
            hello: 'world'
        }))
        done()
    }
})

// 以下是輸出的JSON

{
    "profile": {
        "fail": false,
        "timeout": false,
        "startTime": 1577071246765,
        "finishTime": 1577071246769,
        "totalTime": 4
    },
    "metadata": {
        hello: 'world'
    },
    "template": [
        {
            "name": "sum",
            "logs": {
                "5f0e1c0e-e537-42f3-ab3b-cc6689aada5e": {
                    "logs": {},
                    "startTime": 1577071246768,
                    "name": "sum",
                    "args": [
                        10,
                        20
                    ],
                    "caller": null,
                    "mode": "action",
                    "request": "[]",
                    "response": null,
                    "group": {
                        "name": "math",
                        "sign": ""
                    },
                    "success": true,
                    "result": 30,
                    "finishTime": 1577071246768,
                    "totalTime": 0
                }
            },
            "startTime": 1577071246766,
            "finishTime": 1577071246768,
            "totalTime": 2
        }
    ]
}
```

我們提供了簡易的JSON Template檢視工具來協助你開發：

[History檢視工具](https://khc-zhihao.github.io/Packhouse/tools/step-view/)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://packhouse-doc.metalsheep.com/plugins/step.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
